6

有没有一种方法可以创建一个带有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

4 回答 4

7

如果您不想要Boost C++ Libraries的魔力并且想要裸露的骨骼......

template<bool> class static_check
{
};

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

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

然后使用静态断言。这对我来说是一个#define,因为我的代码需要在许多 C++ 不适用于模板的环境中运行,我需要将其退回到运行时断言。:(

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

于 2009-01-19T22:20:08.400 回答
3
template <int number1>
typename boost::enable_if_c< (number1 >= 10) >::type 
reportErrorIfLessThan10() {
    // ...
}

上面enable_if没有 _c 因为我们有一个普通的布尔值,看起来像这样:

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

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

Boostenable_if采用纯布尔值,因此它们有另一个附加了 _c 的版本,它采用纯布尔值。您将无法将其称为number1< 10。SFINAE将排除该模板作为可能的候选者,因为如果条件评估为,enable_if则不会公开类型。如果您出于某种原因想要在函数中对其进行测试,那么如果您有可用的C++1x功能,则可以使用:::typefalsestatic_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

于 2009-01-19T22:12:44.187 回答
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");比 say 更具可读性static_assert(true, some_message);。但是,这确实将用例限制为每行只有一个断言。

于 2009-01-19T22:27:30.413 回答
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 生成 case,它们是硬编码递归的开始。

顺便说一句,上面的代码实际上给出了很好的错误信息:

x.cpp:16: error: no matching function for call to 'error_if_less_than_10()'
于 2009-01-19T22:26:45.330 回答