具有未定义成员函数返回类型的模板实例化

时间:2016-08-08 07:30:23

标签: c++ templates c++11 c++14 auto

struct Value {
    using a_type = int;
    a_type f() { return 1; }
};

template<typename T>
struct Wrapper {
    T t;
    auto call_f() { return t.f(); }
};

int main() {
    Wrapper<Value> w;
    Wrapper<int> w2;
    w.call_f();
}

这对Clang和GCC很好。即使Wrapper<int>的返回类型无法推断(没有Wrapper<int>::call_f()),int::f()也会被实例化。只有在w2.call_f()被调用时它才会失败。

这是C ++标准的一部分,是否可以在所有编译器上运行?

2 个答案:

答案 0 :(得分:11)

是的,这是C ++标准的一部分。

模板实例化的规则冗长而复杂,但简短版本是模板类的成员函数仅在需要时实例化。如果没有任何东西调用它,或者尝试获取它的指针,或者显式地实例化它(可能还有其他一些我忘记的情况),那么它就不会被实例化并且你的代码格式正确。

正如@dyp指出的那样,只有在实例化类定义([temp.inst]/1)时实例化的成员函数的声明,但只返回返回类型推导函数定义实例化时([dcl.spec.auto]/12)。

这对于最小化模板的开销和对类型要求的许可非常有帮助。正是这个功能可以让你做到这样的事情:

struct Foo {
    //no default constructor
    Foo(int);
};

std::vector<Foo> foos;

某些std::vector函数(例如resize)要求T是默认构造的,但只要您不调用这些函数,您仍然可以使用其他功能std::vector

答案 1 :(得分:2)

是的,它符合标准。 Wrapper<T>::call_f()只有在被调用时才会被隐式实例化。

$14.7.1/2 Implicit instantiation [temp.inst]

  

除非已明确实例化或明确专门化类模板或成员模板的成员,否则在需要成员定义存在的上下文中引用特化时,将隐式实例化成员的特化;

$14.7.1/8 Implicit instantiation [temp.inst]

  

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