如果永远不会被调用,那么类模板的成员函数是否会被实例化?

时间:2015-11-11 10:00:49

标签: c++ templates

我刚刚开始了解一些模板基础知识。实际上,直到现在我才接受它作为一个事实,但我真的不明白为什么这个被打破了:

template <typename T,bool hasFoo>
struct Broken {
    void foobar(){
        if (hasFoo){T::foo();}
        else { std::cout << "BROKEN" << std::endl;}
    }
};

int main(){
    Broken<int,false> t;
    t.foobar();
}

虽然这有效:

template <typename T>
struct Works {
    void foo(){T::foo();}
    void bar(){std::cout << "WORKS" << std::endl;}
};

int main(){
    Works<int> t;
    t.bar();
}

不知何故很明显,但我只是想确保我没有错过一些东西: 这是否有效,因为如果从未调用函数Works<int>::foo(),它就不会被实例化?

PS:为了避免误解:我知道,为什么Broken被打破,我最近有一个question与此相关,我得到了很好的答案,但之后我认为{{1}我不应该编译,直到我意外地传递了一个“错误的”模板参数,并且惊讶于它确实编译了。

2 个答案:

答案 0 :(得分:7)

  

如果从不调用函数Works :: foo(),它就不会被实例化?

是的,类模板的非虚拟成员函数在需要之前不会被实例化。

从标准§12.8.1/10 Implicit instantiation [temp.inst]

开始

(强调我的)

  

实现不应隐式实例化函数   模板,变量模板,成员模板,非虚拟   成员函数,成员类,类的静态数据成员   模板或constexpr if语句的子语句([stmt.if]),   除非需要这样的实例化。

答案 1 :(得分:1)

要回答标题中的问题,不,不需要实例化它。

此代码无法编译,但从未调用foo

template <typename T>
struct Works {
    void foo(){T::foo();}
    void bar(){}
};

// this requires foo being instantiated because it may be called from
// elsewhere - the compiler cannot know.
template Works<int>; 

int main(){
    Works<int> t;
    t.bar();
}

实时:https://godbolt.org/g/u4frVZ

这就是为什么该标准说除非它需要实例化,否则它不会实例化,并且该规则比是否被调用更为复杂。