Как определить строковый литерал с помощью type_traits?

Как мне надежно static_assert для всего, что не является строковым литералом?

Например, в следующем коде я попытался обернуть стандартный макрос assert, но статически отклонить что-либо для сообщения, которое не является строковым литералом (поскольку все, кроме строкового литерала, не будет отображаться во время выполнения при срабатывании assert).

#include <cassert>
#include <string>
#include <type_traits>

#define my_assert(test, message)\
static_assert(\
(\
!std::is_pointer<decltype(message)>::value &&\
!std::is_array<decltype(message)>::value\
),\
"literal string required"\
);\
assert((message, (test)));

int main() {
my_assert(1 == 1, "one equals one");
my_assert(1 == 2, "one equals two");

{
const char *msg = "one equals one";
//my_assert(1 == 1, msg); // triggers static_assert
}

{
const char msg[] = "one equals one";
//my_assert(1 == 1, msg); // triggers static_assert
}

{
const std::string msg = "one equals one";
//my_assert(1 == 1, msg.c_str()); // triggers static_assert
}

{
const int msg = 3;
my_assert(1 == 1, msg); // should trigger static_assert
}
}

Как вы можете видеть, тестирование выполняется с помощью тестов, предоставленных заголовком type_traits, и,
в основном, этот код работает как задумано (протестировано с gcc 4.7.2). Тем не менее, он специально не ищет строковые литералы, а просто отвергает обычные вещи, которые программист может использовать на месте.

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

Итак, вопрос в том, как мне надежно использовать type_traits (или другой стандартный механизм) для static_assert на что-нибудь кроме строкового литерала?

7

Решение

Вот лучшее, что я мог получить, который, кажется, отклоняет все, что я бросаю в него, но все еще принимает буквальные строки:

#define my_assert(test, message)\
static_assert(\
(\
std::is_convertible      <decltype(message), const char *>::value &&\
!std::is_rvalue_reference <decltype(message)>::value &&\
!std::is_pointer          <decltype(message)>::value &&\
!std::is_array            <decltype(message)>::value &&\
!std::is_class            <decltype(message)>::value\
),\
"string literal required"\
);\
assert((message, (test)))

Мне было бы очень интересно узнать, если это на самом деле является исчерпывающе правильным, и / или если есть более простой способ сделать это обнаружение.

7

Другие решения

‘decltype («некоторая строка»)’ строкового литерала возвращает «const char (&) [n] «тип.
Таким образом, кажется, что это более кратко, по сравнению с следующий ответ, способ его обнаружения:

template<typename T>
struct IsStringLiteral :
std::is_same<
T,
std::add_lvalue_reference_t<const char[std::extent_v<std::remove_reference_t<T>>]>
>
{};

(онлайн демо)

0

По вопросам рекламы [email protected]