static_assert - способ динамически настраивать сообщение об ошибке

Есть ли способ сделать строку static_assert динамически настраиваемой и затем отображаемой?
Я имею в виду что-то вроде:

//pseudo code
static_assert(Check_Range<T>::value, "Value of " + typeof(T) + " type is not so good ;)");

4 ответа

Нет, нет

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

Посмотрите на этот синтетический пример в ideone:

#include <iostream>

template <typename T>
struct IsInteger { static bool const value = false; };

template <>
struct IsInteger<int> { static bool const value = true; };

template <typename T>
void DoSomething(T t) {
  static_assert(IsInteger<T>::value, // 11
  "not an integer");

  std::cout << t;
}

int main() {
  DoSomething("Hello, World!"); // 18
}

Компилятор не только выдает диагностику, но и полный стек:

prog.cpp: In function 'void DoSomething(T) [with T = const char*]':
prog.cpp:18:30:   instantiated from here
prog.cpp:11:3: error: static assertion failed: "not an integer"

Если вы знаете Python или Java и как они печатают стек в случае исключения, это должно быть знакомо. На самом деле, тем не менее, это даже лучше, потому что вы не только получаете стек вызовов, но вы также получаете значения аргументов (типы здесь)!

Поэтому динамические сообщения не так необходимы:)

Стандарт определяет второй аргумент static_assert чтобы быть строковым литералом, так что шансов для вычислений там нет, насколько я вижу (кроме макросов препроцессора).

Компилятор может расширить стандарт и разрешить const-выражения подходящего типа в этой позиции, но я понятия не имею, делает ли это какой-либо компилятор.

Как сказал Матье, это невозможно, но вы можете получить некоторые функции, которые вам нужны, используя макросы:

#define CHECK_TYPE_RANGE(type)\
    static_assert(Check_Range<type>::value, "Value of " #type " type is not so good ;)");

CHECK_TYPE_RANGE(float); // outputs "Value of float type is not so good ;)"

Возможно, есть надежда на C++26. Черновик C++26 меняет C++23.

      static_assert-declaration:
    static_assert ( constant-expression ) ;
    static_assert ( constant-expression , string-literal ) ;

к

      static_assert-message:
    unevaluated-string
    conditional-expression

static_assert-declaration:
    static_assert ( constant-expression ) ;
    static_assert ( constant-expression , static_assert-message ) ;

Надеюсь, это пройдет. Предлагается что-то вроде

      static_assert(sizeof(S) == 1,
std::format("Unexpected sizeof: expected 1, got {}", sizeof(S)));

излучать что-то вроде

      error: static assertion failed due to requirement 'sizeof(S) == 1':
Unexpected sizeof: expected 1, got 4

Редактировать 1: по многочисленным просьбам, ссылка на проект C++26 https://wg21.link/n4964 , раздел 9.1 (стр. 175) и документ для новой unevaluated-string, которые, мы надеемся, сделают больше по мере развития проекта (огонь смайлики в сторону).

Изменение 2: добавлена ​​ссылка на предложение.

Другие вопросы по тегам