【问题标题】:How to do static_assert with macros?如何用宏做static_assert?
【发布时间】:2013-01-31 09:06:40
【问题描述】:

我尝试使用this suggestion 进行静态断言,但如果在模板的方法中使用它,我不会收到编译错误。

示例如下:

#include <iostream>

#define STATIC_ASSERT(expr, msg)               \
{                                              \
    char STATIC_ASSERTION__##msg[(expr)?1:-1]; \
    (void)STATIC_ASSERTION__##msg[0];          \
}

template <typename T >
class A
{
public:
  int foo(const int k )
  {
    // does not work
    STATIC_ASSERT( k > 9, error_msg );
    return k+5;
  }
};

int bar(const int k )
{
  // works fine
  //STATIC_ASSERT( k > 9, error_msg );
  return k+5;
}

int main()
{
  A<int> a;
  const int v = 2;

  std::cout<<a.foo(v)<<std::endl;
  std::cout<<bar(v)<<std::endl;

  // works fine
  //STATIC_ASSERT( v > 9, error_msg );
}

我用 g++ 4.7.2 编译它,并警告说 C++ ISO 不支持 VLA:

g++ -Wall -g  -std=c++98 -Wextra -pedantic gvh.cpp

那么,为什么在模板方法中使用 STATIC_ASSERT 时编译不会失败?有没有办法让它失败?

注意:我需要一个 c++98(甚至可能是 c++03)的解决方案,如果可能的话,只能使用宏。

【问题讨论】:

  • Boost 有一个 pre-C++11 静态断言。
  • @chris 是的,我知道 BOOST_STATIC_ASSERT,但它使用 SFINAE 进行检查。
  • 在答案和上面有很好的建议,关于哪些静态断言机制存在,但更根本的是,在你的具体用法中,你试图对函数参数进行断言 - 只是因为它是 const int 没有'这意味着它是编译时常量——这只是意味着该函数获取运行时参数的副本,并且不允许被调用的代码修改它。您需要接受k 作为模板参数(对于A 或通过将A::foo 设置为template &lt;int K&gt;,或者可能使用C++11 constexpr,以获得编译时间检查你'期待。

标签: c++ macros g++ static-assert c++98


【解决方案1】:

在 C++11 之前我通常会这样做:

typedef int static_assert_something[something ? 1 : -1];

您也可以查看boost static assert。但它太臃肿了,我不喜欢。做大很容易,做更好很难。

【讨论】:

  • 只是为了清楚起见(我一直讨厌 typedef 语法):这可以通过尝试根据真值将 typedef 设置为大小为 1 或 -1 的数组来工作?
  • @TimSeguine 正确。
【解决方案2】:

考虑像Boost.StaticAssert 这样的东西,不过如果您无法使用,您可以尝试定义一个模板。

template<bool>
struct static_assertion;

template<>
struct static_assertion<true> {};

虽然它的缺点是没有与之关联的消息。

在通过 StackOverflow 进行一些搜索后,我偶然发现了 this question,它与我的答案相似,并且有很多替代方案可以在没有提升的情况下执行此操作。

【讨论】:

  • 不过你无法击败the one-liner
  • @MaximYegorushkin 我并没有试图统一你的答案。这正是我会做的方式。
  • 谢谢。这个问题的答案类似于 Maxim 的,带有宏
【解决方案3】:

这基本上是 Maxim 的答案,界面更方便。我从here 拿走了它。这样做的好处是模板的使用可以防止用户将非编译时常量值作为条件传递。

template<bool Is_Condition_Met>
struct Static_assert_cpp98
{
  static void apply() {static const char junk[ Is_Condition_Met ? 1 : -1 ];}
};

template<>
struct Static_assert_cpp98<true>
{
  static void apply() {}
};

#define STATIC_ASSERT_CPP98(condition) Static_assert_cpp98<condition>::apply()

【讨论】:

    【解决方案4】:

    如果您添加对相关方法的调用 (a.foo();),静态断言将失败(然后该方法将被编译)。你知道你不应该静态断言运行时值,比如我认为的“k”。

    【讨论】:

    • 是的,但我假设(错误地)编译器会看到 k 的值(就像调用 bar 时看到的一样)
    【解决方案5】:
    int foo(const int k)
    {
      STATIC_ASSERT( k > 9, error_msg );
      return k+5;
    }
    

    静态断言仅适用于编译时常量表达式。

    k 不是编译时常量表达式。

    非类型模板参数是模板实例化期间的编译时常量表达式,因此您可以这样调整代码:

    template <int K>
    int foo()
    {
      STATIC_ASSERT( K > 9, error_msg );
      return K+5;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-30
      • 2010-12-11
      • 2023-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-01
      相关资源
      最近更新 更多