调用专用模板函数时强制编译时错误
Force compile time error when specialized template function is invoked
我有一个模板函数。只要实参不是指针类型,它就具有定义良好的语义。如果有人调用这个函数传递类型指针的参数,我想强制编译时错误。编写通用(合法)模板和相应的部分专门化(非法)版本没有问题。我只是不知道如何将错误从函数定义推迟到函数调用。
使用c++ 0x:(参见http://ideone.com/ZMNb1)
#include <type_traits>
#include <iostream>
template <typename T>
void cannot_take_pointer(T ptr)
{
static_assert(!std::is_pointer<T>::value,
"cannot_take_pointer requires non-pointer argument");
std::cout << "okn";
}
int main()
{
int x;
cannot_take_pointer(x);
cannot_take_pointer(&x); // fails to compile
}
实际上你不需要专门化它。只需在函数体中添加以下内容:
BOOST_STATIC_ASSERT(!boost::is_pointer<T>()::value);
这将导致一个应该相当容易理解的错误
听起来像是boost::disable_if
的完美案例。这样应该可以工作。
template <class T>
void func(T x, typename boost::disable_if<boost::is_pointer<T> >::type* dummy = 0) {
std::cout << x << std::endl;
}
func(10); // works
func(std::string("hello")); // works
func("hello world"); // error: no matching function for call to 'func(const char [6])'
func(new int(10)); // error: no matching function for call to 'func(int*&)'
如果您想自己做这件事(而不是使用BOOstrongTATIC _ASSERT之类的东西),通常会涉及到两三个基本技巧。
第一个(可能是最重要的,在您的情况下)是使用sizeof
(通常将结果转换为void
)来编译一些代码,而不产生将在编译时执行的任何。
第二种是生成一些在适当情况下是非法的代码。一个典型的方法是创建一个数组,它的大小等于某个表达式的值。如果表达式的值为0,则数组的大小为0,这是不允许的。或者,如果大小为1,则是合法的。这样做的一个问题是,它产生的错误消息通常是相当无意义的——很难猜测"error: array必须有正大小"(或类似的东西)与"模板形参不能是指针"有什么关系。
要产生更有意义的错误消息,通常使用一种稍微不同的技巧。在这种情况下,从一个类到另一个类的转换,如果表达式为假将失败,但如果表达式为真则成功。这样做的一种方法是:
template <bool>
struct check { check(...); };
template <>
class check<false> {};
check(...);
意味着任何其他类型都可以(理论上)转换为check<true>
(但请注意,我们只声明函数,从不定义它,所以如果您试图执行这样的代码,它将无法链接)。check<false>
中没有any转换构造函数,这意味着试图将其他任何东西转换为check<false>
总是会失败。
我们可以像这样在宏中使用它:
#define STATIC_ASSERT(expr, msg) {
struct Error_##msg {};
(void)sizeof(check<(expr)!=0>((Error_##msg)));
}
你可以这样使用:STATIC_ASSERT(whatever, parameter_cannot_be_a_pointer);
。它可以展开为:
struct Error_parameter_cannot_be_a_pointer {};
(void)sizeof(check<(expr)!=0>(Error_parameter_cannot_be_a_pointer);
然后,如果expr
!= 0,它将尝试将Error_parameter_cannot_be_a_pointer转换为check<true>
,这将成功。
expr
不等于0,它将尝试转换为check<false>
,这将失败。我们至少希望当发生这种情况时,我们得到一个类似这样的错误消息:
error cannot convert:
Error_parameter_cannot_be_a_pointer
to
check<false>
显然,如果我们可以的话,我们想要一个更好的消息,但即使是这样,这也不是太糟糕。您只需要忽略"包装",并查看源类型的名称,就可以很好地了解问题所在。
- C++ 在编译时具有函数计算全局变量
- 在缺少函数重载时抛出异常,并带有 std::variant 而不是编译时错误
- 在编译时评估函数开销的通用方法
- 如何在常量计算表达式中获取编译时错误?
- 有没有办法在C++编译时更改函数原型?
- C++根据调用的构造函数强制编译时错误
- 使用 std::iterator_traits<> 时编译时错误不明确
- 尝试调用指向成员函数的函数指针时出现编译时错误
- 编译时错误:删除了联合默认构造函数
- 函数指针 - 编译时错误
- 函数编译时错误
- C++中与主函数对应的编译时错误
- C++:使用类型名作为基的模板类调用函数编译时错误
- 2个c源文件之间的函数指针操作导致编译时错误
- 如果条件不满足,调用函数时会出现编译时错误
- 作为私有的析构函数抛出编译时错误
- map非const函数,在clang++下编译时错误,适用于g++
- 调用专用模板函数时强制编译时错误
- 编译时错误:期望的构造函数、析构函数或转换
- 在工厂中使用指针函数会产生编译时错误