Предположим, у нас есть шаблонная функция с параметром не типа const char *
, например:
template <const char * MESSAGE> void print() {
std::cout << MESSAGE << '\n';
}
Использование этого шаблона не будет проблемой, поскольку журнал MESSAGE
может быть выведен во время компиляции, поэтому следующие варианты использования допустимы:
namespace {
char namespace_message[] = "Anonymous Namespace Message";
constexpr char namespace_constexpr_message[] = "Anonymous Namespace Constexpr Message";
}
char message[] = "Message";
constexpr char constexpr_message[] = "Constexpr Message";
int main()
{
print<namespace_message>();
print<namespace_constexpr_message>();
print<message>();
print<constexpr_message>();
return 0;
}
Но приведенные ниже не являются (см. Здесь):
namespace {
const char namespace_const_message[] = "Anonymous Namespace Const Message";
}
const char const_message[] = "Const Message";
int main()
{
print<namespace_const_message>();
print<const_message>();
print<"Literal">();
return 0;
}
Ошибки, сгенерированные приведенным выше кодом, следующие:
значение '{anonymous} :: namespace_const_message' не может использоваться в постоянном выражении
Я не понимаю, почему namespace_const_message
нельзя использовать в постоянном выражении, а namespace_message
-; если я должен сделать ставку на то, что одно из них нельзя будет использовать в постоянном выражении, я сделаю ставку на отсутствие констант, но это тот, который уже работает как постоянное выражение!
примечание: '{anonymous} :: namespace_const_message' не был объявлен 'constexpr'
namespace_message
не был объявлен как constexpr
и используется в константном выражении, и его значение выводится во время компиляции. Зачем constexpr
, если выражение const
и не требуется, если no-const?
То же самое касается значений за пределами анонимного пространства имен, я пытался заставить постоянство времени компиляции помещать значения во внутреннее пространство ссылок, но очевидно, что я потерпел неудачу.
Наконец, последняя ошибка:
"Literal" "не является допустимым аргументом шаблона для типа" const char * ", потому что строковые литералы никогда не могут использоваться в этом контексте.
Итак, на удивление (по крайней мере, для меня это было неожиданностью) строковый литерал не может использоваться в качестве аргумента шаблона, но пока строка (ну, указатель на массив символов с завершающим нулем) является значением времени компиляции, она могут использоваться как параметры шаблона, не относящиеся к типу, поэтому: они доступны во время компиляции, если «они являются lvalue» (но они уже lvalues !).
Я пытаюсь угадать, почему строковый литерал никогда не может использоваться в этом контексте, и я могу предположить, что два строковых литерала с одинаковым содержимым не являются одним и тем же литералом (потому что указатель, указывающий на содержимое, может быть другим) в то время как два интегральных литерала одинаковы (они являются значением, а не указателем на значение).
Итак, в чем вопрос?
- Почему
namespace_const_message
иconst_message
недоступны во время компиляции и поэтому запрещены в функции шаблонаprint
? - Верно ли мое предположение о строковых литералах?
Спасибо.