C ++:为什么编译器在不使用时实例化模板

时间:2015-07-01 22:37:08

标签: c++ templates arguments instantiation

让我们考虑一下这段代码:

template <bool c>
class A {
public:
    A() = default;
    // I want to enable f(int) only if c == true
    template<typename Temp = typename enable_if<c>::type>
    void f(int val) {
        cout << val << endl;
    };
};

int main() {
    A<false> a;
    A<true> b;
    b.f(543);
}

当我尝试编译时,我收到以下错误:

error: no type named 'type' in 'struct std::enable_if<false, void>'

但是,当参数f(int)<bool c>时,我不会使用模板方法false,那么它就不应该存在。

1 个答案:

答案 0 :(得分:2)

编译器不会“实例化”您的模板,因为您似乎错误地相信。编译器只是试图解析和分析模板声明,这是类定义的一部分。如果实例化了类,则所有成员声明必须有效。您的成员模板声明无效。因此错误。

如果某个模板“未使用”,则意味着它没有得到专门化和实例化。但该模板的声明仍然必须有效。并立即检查不依赖于模板参数的声明部分的有效性。换句话说,您在代码中编写的内容与

没有什么不同
template <typename T = jksgdcaufgdug> void foo() {}

int main() {}

或者,更接近您的情况

template <typename T = std::enable_if<false>::type> void foo() {}

int main() {}

即使这些程序没有“使用”(不实例化)函数模板foo,它仍然不意味着foo的声明可能包含jksgdcaufgdug之类的随机垃圾或显式引用不存在的实体,如std::enable_if<false>::type。由于这个原因,上面的例子不会编译。

您可以在依赖上下文中使用“随机垃圾”,例如

template <typename T> void foo(typename T::kjhdfjskhf x) 
{ 
  typename T::jksgdcaufgdug i; 
}

您可以在依赖的上下文中使用std::enable_if,例如

template <typename T, 
          typename U = typename enable_if<is_void<T>::value>::type>
void bar()
{ 
}

并且它不会产生“早期”错误,但在您的情况下,enable_if<c>不依赖于Temp,因此它不在依赖的上下文中。这意味着在您实例化typename enable_if<c>::type时会立即检查A<false>的正确性。