有更好的方法来执行以下操作吗?
#include <iostream>
template <typename T>
T Bar();
template <>
int Bar<int>() { return 3; }
// Potentially other specialisations
int main()
{
std::cout << Bar<int>() << std::endl; // This should work
std::cout << Bar<float>() << std::endl; // This should fail
}
这个解决方案的问题在于它(可理解地)链接时间与“未定义引用浮动Bar<float>()
”等失败。这可能会让其他开发人员感到困惑,因为他们可能怀疑实现文件没有被链接。
我知道另一种可能的解决方案:
template <typename T>
T Bar() { BOOST_STATIC_ASSERT(sizeof(T) == 0); }
这会在请求Bar<float>()
时导致编译器错误,这正是我想要的。但是,我担心技术上编译器可能会拒绝这一点,就像gcc拒绝BOOST_STATIC_ASSERT(false)
一样,因为它知道无论模板参数如何都会失败,因为sizeof(T)
永远不会为零。
总之,我想知道是否:
BOOST_STATIC_ASSERT(sizeof(T))
实际上没有实例化就失败了。答案 0 :(得分:6)
这可行:
template <typename T>
T Bar() {
T::ERROR_invalid_template_argument_;
}
template <>
int Bar<int>() { return 3; }
如果您害怕使用0:
,您也可以使用最大尺寸 static_assert(sizeof(T) == -1, "No specialization");
答案 1 :(得分:4)
BOOST_STATIC_ASSERT(sizeof(T) == 0);
失败,所以我只会这样做。你是正确的BOOST_STATIC_ASSERT(false);
每次触发。
这个原因与两阶段名称查找有关。这基本上是以下内容:编译模板时,它被编译两次。 compielr第一次看到模板时,它会编译所有,除了依赖于模板参数的表达式,第二次编译在模板参数已知时发生,完全编译实例化。
这就是为什么BOOST_STATIC_ASSERT(false);
将永远失败的原因:此处没有任何依赖,并且会立即处理断言,就好像该函数根本不是模板一样。 (请注意,MSVC不实现两阶段查找,因此在实例化时会失败,这是错误的。)相反,因为T
是依赖的(§14.6.2.1),BOOST_STATIC_ASSERT(sizeof(T) == 0);
是依赖的,并且是在模板实例化之前不允许检查。 (如果它永远都会失败。)
如果编译器试图考虑周到并且提前失败,那么它将是不符合的。你可以依靠这些东西。也就是说,如果恐惧变得最好,那么真的让它等待是微不足道的:
BOOST_STATIC_ASSERT(sizeof(typename T::please_use_specializations) == 0);
这两者都保证失败,并且编译器无法提前正确“智能地”失败。
答案 2 :(得分:0)
您可以执行以下操作:
template <typename T>
T Bar()
{ T::unspecialized_method_called; }
这当然假设T没有具有给定名称的成员,因此您必须相应地选择“错误消息”(例如,违反命名约定)。
答案 3 :(得分:0)
将static_assert与c ++ 0x
一起使用template <typename T>
void bar(){
static_assert(false, " invalid argument type");
}
这会在编译时引发错误。
对于c ++ 98/2003,我们可以试试这个
template <typename T>
void bar(){
char invalid_arg_[0];
}
数组至少包含一个元素。所以编译器会抱怨。但错误信息可能无法显示发生的事情。
第一个不会是一个选择,因为它总是失败。
答案 4 :(得分:0)
如果您使用的是没有-pedantic的gcc,有一点需要注意,在这种情况下 可能有sizeof(T) == 0
- 当T
是零长度数组时
#include <iostream>
#include "boost/static_assert.hpp"
template <typename T>
void Foo()
{
BOOST_STATIC_ASSERT(sizeof(T) == 0);
std::cout << "Actually, it is possible to instantiate this." << std::endl;
}
int main()
{
Foo<int[0]>();
return 0;
}
在这种情况下,你可以通过使用它来解决它:
BOOST_STATIC_ASSERT(sizeof(T) == sizeof(T) + 1);
封装这个技巧可能会更好,这可以提高可读性,因为它表达了你的意图:
#define NEVER_INSTANTIATE(T) BOOST_STATIC_ASSERT(sizeof(T) == sizeof(T) + 1);
正如GMan解释的那样,如果没有sizeof(T) == 0
的实例化,这不会失败。但是,这个故事的寓意应该是总是用-pedantic 编译。