C ++元编程 - 在代码中生成错误

时间:2009-01-19 22:09:42

标签: c++ templates metaprogramming

有没有办法可以创建一个带有int模板参数的函数,如果传递给函数的值小于10,那么该函数会产生编译时错误?

以下代码不起作用,但它显示了我想要完成的任务:

template <int number1>
void reportErrorIfLessThan10()
{
    #if(number1 < 10)
        #error the number is less than 10
    #endif
}


int maint(int argc, char**argv)
{
   reportErrorIfLessThan10<5>();//report an error!
   reportErrorIfLessThan10<12>();//ok
   return 0;
}

4 个答案:

答案 0 :(得分:7)

如果你不想要Boost C++ Libraries魔法并想要骨头......

template<bool> class static_check
{
};

template<> class static_check<false>
{
private: static_check();
};

#define StaticAssert(test) static_check<(test) != 0>()

然后使用StaticAssert。这对我来说是一个#define,因为我的代码需要在很多C ++不适合模板的环境中运行,我需要将它备份到运行时断言。 :(

此外,不是最好的错误消息。

答案 1 :(得分:3)

template <int number1>
typename boost::enable_if_c< (number1 >= 10) >::type 
reportErrorIfLessThan10() {
    // ...
}

以上enable_if,没有_c,因为我们有一个普通的bool,看起来像这样:

template<bool C, typename T = void>
struct enable_if {
  typedef T type;
};

template<typename T>
struct enable_if<false, T> { };

Boostenable_if不是一个简单的bool,所以他们有另一个附加了_c的版本,它采用普通的bool。您将无法为number1&lt; 10. SFINAE 会将该模板排除为可能的候选者,因为如果条件评估为enable_if::type将不会公开类型false。如果您因某种原因需要在功能中测试它,那么如果您有C++1x功能,则可以使用static_assert

template <int number1>
void reportErrorIfLessThan10() {
    static_assert(number >= 10, "number must be >= 10");
}

如果没有,您可以使用BOOST_STATIC_ASSERT:

template <int number1>
void reportErrorIfLessThan10() {
    BOOST_STATIC_ASSERT(number >= 10);
}

显示描述性消息的唯一方法是使用static_assert。您可以使用具有描述错误条件的名称的类型来或多或少地模拟它:

namespace detail {
    /* chooses type A if cond == true, chooses type B if cond == false */
    template <bool cond, typename A, typename B>
    struct Condition {
      typedef A type;
    };

    template <typename A, typename B>
    struct Condition<false, A, B> {
      typedef B type;
    };

    struct number1_greater_than_10;
}

template <int number1>
void reportErrorIfLessThan10() {
    // number1 must be greater than 10
    sizeof( typename detail::Condition< (number1 >= 10), 
             char, 
             detail::number1_greater_than_10 
            >::type ); 
}

它在这里打印:

  

错误:'sizeof'无效应用于不完整类型'detail :: number1_greater_than_10'

但我认为使用enable_if的第一种方法就是这样做的。您将收到有关未申报reportErrorIfLessThan10的错误消息。

答案 2 :(得分:3)

如果出于某种原因你不能使用Boost,这个例子很简单:

template <int number1>
void reportErrorIfLessThan10()
{
    typedef char number1_gt_10[number1 > 10 ? 1 : -1];
}


int maint(int argc, char**argv)
{
   reportErrorIfLessThan10<5>();//report an error!
   reportErrorIfLessThan10<12>();//ok
   return 0;
}

或更通用的

#define static_assert(test, message) typedef char static_assert_at_ ## __LINE__[(test) ? 1 : -1];

我没有连接错误消息本身,因为我觉得static_assert(true, "some message");static_assert(true, some_message);更具可读性。但是,这确实将用例限制为每行只有一个断言。

答案 3 :(得分:0)

litb和Joe已经给出了实践中使用的答案。只是为了说明如何通过专门针对有问题的数字(而不是一般的布尔条件)手动完成:

template <int N>
struct helper : helper<N - 1> { };

template <>
struct helper<10> { typedef void type; };

template <>
struct helper<0> { }; // Notice: missing typedef.

template <int N>
typename helper<N>::type error_if_less_than_10() {
}

int main() {
    error_if_less_than_10<10>();
    error_if_less_than_10<9>();
}

函数不能继承,但类(和结构)可以。因此,此代码还使用一个结构,自动和动态生成除10和0之外的所有N的情况,这是硬编码的递归开始。

顺便说一句,上面的代码实际上提供了很好的错误消息:

x.cpp:16: error: no matching function for call to 'error_if_less_than_10()'