How to do static_assert with macros?

2019-01-12 08:37发布

问题:

I have tried to use this suggestion to do a static assert, but I do not get a compilation error if I use it within a method of a template.

The example follows :

#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 );
}

I compiled it with g++ 4.7.2, with a warning that VLAs are not supported by c++ ISO :

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

So, why the compilation doesn't fail when the STATIC_ASSERT is used within the template method? Is there a way to make it fail?

NOTE : I need a c++98 (maybe even c++03) solution, if possible only with macros.

回答1:

Prior to C++11 I would normally do:

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

You can also look at boost static assert. But it is too bloated for my liking. It is easy to make things bigger, it is hard to make them any better.



回答2:

Consider something like Boost.StaticAssert, although if that is unavailable to you you can try defining a template.

template<bool>
struct static_assertion;

template<>
struct static_assertion<true> {};

Though that has the drawback of not having a message associated to it.

After a bit of searching through StackOverflow, I stumbled upon this question which had a similar answer to mine and a bunch of alternatives for doing it without boost.



回答3:

This is basically Maxim's answer with a little more convenient interface. I have taken it from here. Nice thing about it is that the use of templates prevents the user from passing a non-compile-time-constant value as the condition.

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:

If you add call to the method in question (a.foo();), the static assert will fail (just then the method will be compiled). You do know that you should not static assert on run time values like "k" I presume.



回答5:

int foo(const int k)
{
  STATIC_ASSERT( k > 9, error_msg );
  return k+5;
}

Static assertions only work with compile-time constant expressions.

k is not a compile-time constant expression.

Non-type template parameters are compile-time constant expressions during template instantiation, so you could adapt your code thus:

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