如果实例化,如何使模板化变量特化在编译时失败?
How can I make a templated variable specialization fail at compile time if instantiated?
当且仅当模板变量的默认特化被实例化时,是否有可能出现编译时错误?例如
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
之类的机制以某种方式报告错误,这样就更好了,这样它至少在某种程度上是清晰的。
你应该问问语言律师这是否标准。 Clang 不会让您保留未定义的模板化 constexpr 变量,但它会让您从 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>'
}
gcc
不喜欢模板实例化中的 static
关键字。
但只保留未定义的默认模板似乎可以解决问题:
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> {
// ...
};
同样的事情。
基于 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"
}
当且仅当模板变量的默认特化被实例化时,是否有可能出现编译时错误?例如
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
之类的机制以某种方式报告错误,这样就更好了,这样它至少在某种程度上是清晰的。
你应该问问语言律师这是否标准。 Clang 不会让您保留未定义的模板化 constexpr 变量,但它会让您从 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>'
}
gcc
不喜欢模板实例化中的 static
关键字。
但只保留未定义的默认模板似乎可以解决问题:
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> {
// ...
};
同样的事情。
基于 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"
}