Как сделать static_assert с макросами?

Я пытался использовать это предложение для статического утверждения, но я не получаю ошибку компиляции, если я использую его в методе шаблона.

Пример следует:

#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, с предупреждением, что VLA не поддерживаются C++ ISO:

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

Итак, почему компиляция не завершается неудачно, когда в методе шаблона используется STATIC_ASSERT? Есть ли способ заставить его потерпеть неудачу?

ПРИМЕЧАНИЕ: мне нужно решение C++98 (возможно, даже C++03), если возможно только с макросами.

5 ответов

Решение

До C++11 я обычно делал:

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

Вы также можете посмотреть на повышение статического утверждения. Но это слишком раздутый на мой вкус. Легко сделать вещи больше, трудно сделать их лучше.

Это в основном ответ Максима с немного более удобным интерфейсом. Я взял это отсюда. Хорошая вещь об этом - то, что использование шаблонов препятствует тому, чтобы пользователь передал значение не-времени компиляции как условие.

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()

Рассмотрим что-то вроде Boost.StaticAssert, хотя, если он вам недоступен, вы можете попробовать определить шаблон.

template<bool>
struct static_assertion;

template<>
struct static_assertion<true> {};

Хотя у этого есть недостаток отсутствия сообщения, связанного с ним.

После небольшого поиска в Stackru я наткнулся на этот вопрос, у которого был аналогичный мне ответ и куча альтернатив для выполнения этого без повышения.

Если вы добавите вызов к рассматриваемому методу (a.foo();), статическое утверждение не будет выполнено (только тогда метод будет скомпилирован). Вы знаете, что вы не должны статически утверждать значения времени выполнения, такие как "k", я полагаю.

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;
}
Другие вопросы по тегам