如果实例化,如何在编译时使模板化变量特化失败?

时间:2016-04-23 22:25:20

标签: c++ templates template-meta-programming

当且仅当模板化变量的默认特化被实例化时,是否可能出现编译时错误?例如

template<typename T>
constexpr int foo = /* Something that fails */;

template<>
constexpr int foo<bool> = 42;

// ...
int bar = foo<bool>; // All good!
int meow = foo<int>; // Error if and only if this line exists

即使专业化没有被实例化,我尝试输入/* Something that fails*/的所有内容最终都失败了。这可能吗?如果错误可以通过像static_assert这样的机制进行报告,那么它就更好了。

3 个答案:

答案 0 :(得分:4)

如果这是标准的,你应该问语言律师。 Clang不会让你留下模板化的constexpr变量undefined,但它会让你从constexpr初始化器中引用未定义的模板实例。然后你可以这样写:

template<typename T>
struct no_such_type_for_foo;

template<typename T>
constexpr int foo = no_such_type_for_foo<T>::value;

template<>
constexpr int foo<int> = 4;

int main()
{
    int y = foo<int>; // all good
    int z = foo<bool>; // implicit instantiation of undefined template 'no_such_type_for_foo<bool>'
}

答案 1 :(得分:1)

gcc不喜欢模板实例化中的static关键字。

但是保留默认模板undefined似乎可以解决问题:

template<typename T>
constexpr int foo;

template<>
constexpr int foo<bool> = 42;

有了这个,这有效:

std::cout << foo<bool> << std::endl;

然后失败了:

std::cout << foo<char> << std::endl;

使用:

t.C:2:15: error: uninitialized const ‘foo<char>’ [-fpermissive]
 constexpr int foo;
               ^

我认为这种情况与未定义默认模板的更常见情况之间没有太大区别:

template<typename T> class foo;

template<>
class foo<char> {

// ...
};

同样的事情。

答案 2 :(得分:0)

根据zneak和Sam的解决方案,我想出了一个允许通过static_assert自定义错误消息的变体。关键是static_assert条件需要依赖于模板参数,否则将立即评估模板是否实际使用。

问题在于我们希望static_assert无条件地失败,因此对于每个可能的参数,条件应该减少到false。我们依靠编译器本身不进行分析(我不确定如果模板没有实例化,是否真的可以解决它。)

template<typename T>
constexpr int no_such_type_for_foo()
{
    static_assert(sizeof(T) < 0, "No such type for foo");
    return 0;
}

template<typename T>
constexpr int foo = no_such_type_for_foo<T>();

template<>
constexpr int foo<bool> = 42;

int main()
{
    int y = foo<bool>; // all good
    int z = foo<int>; // static_assert failed "No such type for foo"
}