如何在编译时如果实例化模板变量专业化失败?
问题描述:
当且仅当模板变量的默认特化被实例化时,是否有可能获得编译时错误?例如如何在编译时如果实例化模板变量专业化失败?
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
这样的机制以某种方式报告错误,那么它至少有点清晰。
答
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"
}
不幸的是,clang并没有如此放纵:'错误:const类型'const int'对象的默认初始化(即使没有在任何地方引用)。 – Trillian
如何:template constexpr int foo = std :: enable_if :: value> :: type(); –