Как да направя 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 като template <int K>, или може би да си поиграете с C++11 constexpr, за да получите проверката на времето за компилиране, която очаквате.   -  person Tony Delroy    schedule 31.01.2013


Отговори (5)


Преди C++11 обикновено бих направил:

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

Можете също да разгледате усилване на статичното твърдение. Но е твърде надут за моя вкус. Лесно е да направиш нещата по-големи, трудно е да ги направиш по-добри.

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

Това е основно отговорът на Maxim с малко по-удобен интерфейс. Взех го от тук. Хубавото в това е, че използването на шаблони не позволява на потребителя да предаде некомпилирана времеконстантна стойност като условие.

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