Как сделать 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), если возможно, только с макросами.


person BЈовић    schedule 31.01.2013    source источник
comment
Boost имеет статическое утверждение до C ++ 11.   -  person chris    schedule 31.01.2013
comment
@chris Да, я знаю о BOOST_STATIC_ASSERT, но он использует SFINAE для проверки.   -  person BЈовић    schedule 31.01.2013
comment
В ответах и ​​выше есть хороший совет о том, какие статические механизмы утверждения существуют, но, что более важно, в вашем конкретном использовании вы пытаетесь утверждать параметр функции - просто потому, что это const int не означает, что это константа времени компиляции - это просто означает, что функция принимает копию аргумента среды выполнения и не позволяет вызываемому коду изменять его. Вам нужно будет принять k в качестве параметра шаблона (либо для A, либо сделав A::foo a template <int K>, или, может быть, возиться с C ++ 11 constexpr, чтобы получить ожидаемую вами проверку времени компиляции.   -  person Tony Delroy    schedule 31.01.2013


Ответы (5)


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

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

Вы также можете посмотреть boost static assert. Но на мой вкус он слишком раздут. Легко делать что-то больше, трудно сделать что-то лучше.

person Maxim Egorushkin    schedule 31.01.2013
comment
Просто для ясности (я всегда ненавидел синтаксис typedef): это работает, пытаясь сделать typedef для массива размером 1 или -1 в зависимости от значения истины? - person Tim Seguine; 27.04.2018
comment
@TimSeguine Правильно. - person Maxim Egorushkin; 30.04.2018

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

template<bool>
struct static_assertion;

template<>
struct static_assertion<true> {};

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

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

person Rapptz    schedule 31.01.2013
comment
Однако вы не можете победить однострочник. - person Maxim Egorushkin; 31.01.2013
comment
@MaximYegorushkin Я не пытался придумать ваш ответ. Я бы так и поступил. - person Rapptz; 31.01.2013
comment
Спасибо. На этот вопрос есть ответ, аналогичный ответу Максима, с макросами. - person BЈовић; 31.01.2013

По сути, это ответ Максима с чуть более удобным интерфейсом. Я взял его person Hashimoto    schedule 04.03.2018


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

person Community    schedule 31.01.2013
comment
Да, но я предположил (ошибочно), что компилятор увидит значение k (как он видит, когда вызывается bar) - person BЈовић; 31.01.2013

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;
}
person Oktalist    schedule 20.03.2014