Некоторые const char * недоступны во время компиляции?
Предположим, что мы имеем функцию шаблона с параметром не-типа 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
-; если я должен сделать ставку на то, что один из них не может быть использован в постоянном выражении, я буду держать пари за константу, но это тот, который уже работает как постоянное выражение!
note: '{anonymous}:: namespace_const_message' не был объявлен 'constexpr'
namespace_message
не был объявлен как constexpr
и используется в константном выражении, и его значение выводится во время компиляции. Почему constexpr
требуется, если выражение const
и не требуется, если no-const?
То же самое относится к значениям вне анонимного пространства имен, я пытался заставить compile-time-constness помещать значения во внутреннее пространство связей, но очевидно, что я потерпел неудачу.
Наконец, последняя ошибка:
' "Literal" ' не является допустимым аргументом шаблона для типа 'const char *', потому что строковые литералы никогда не могут использоваться в этом контексте
Итак, неожиданно (по крайней мере, это было для меня неожиданностью) строковый литерал не может использоваться в качестве аргумента шаблона, но до тех пор, пока строка (ну, указатель на массив символов с нулевым символом) является компилятором, значение времени можно использовать в качестве параметров непигового шаблона так: они доступны во время компиляции, пока "они являются lvalue" (но они уже lvalues !).
Я пытаюсь угадать, почему строковый литерал никогда не может использоваться в этом контексте, и я полагаю, что два строковых литерала с одним и тем же содержимым не являются одинаковыми буквами (поскольку указатель, указывающий на содержимое, может быть разными), тогда как два интегральных литерала одинаковы (они являются значением, а не указателем на значение).
Итак, какой вопрос здесь?
- Почему
namespace_const_message
и const_message
недоступны во время компиляции и поэтому запрещены в функции шаблона print
?
- Мое предположение о правильности строковых литералов?
Спасибо.
Ответы
Ответ 1
Атрибут экземпляра шаблона должен иметь внешний
и const
была неявно внутренней связью. Таким образом, вы должны
написать:
extern char const constMessage[] = "Const message";
(Другой альтернативой может быть статический член класса.
У статических членов класса всегда есть внешняя связь.)
Случай строковых литералов в некотором роде похож: их тип
char const[]
. Но это еще хуже: создание шаблонов (по крайней мере
ранние) нуждаются в имени, а строковый литерал его не имеет.
Еще более важно то, что не указано, идентичны ли строковые литералы
являются одним и тем же объектом или нет, поэтому в следующем:
template <char const* m>
struct Toto { char const* f() const; };
Toto <"titi"> t1;
Toto <"titi"> t2;
было бы неуказано, были ли типы t1
и t2
или нет.
Ответ 2
Из стандарта С++ 11 §14.3.2.1
Шаблон аргументов non-type
Аргумент шаблона для непигового шаблона-шаблона без шаблона должен быть одним из следующих:
- для нетипового шаблона-параметра интегрального или перечисляемого типа, преобразованное постоянное выражение (5.19) типа Шаблон-параметры; или
- имя несимметричного шаблона; или
- постоянное выражение (5.19), которое обозначает адрес объект со статическим временем хранения и внешней или внутренней связью или функцию с внешней или внутренней связью, включая функцию шаблоны и шаблоны-шаблоны функций, но исключая нестатический класс члены, выраженные (игнорируя круглые скобки) как и id-выражение, за исключением что и может быть опущено, если имя относится к функции или массиву и должен быть опущен, если соответствующий шаблон-параметр является Справка; или
- константное выражение, которое вычисляет значение нулевого указателя (4.10); или
- константное выражение, которое вычисляет значение указателя нулевого элемента (4.11); или
- указатель на элемент, выраженный как описано в 5.3.1; или
- выражение константы адреса типа std:: nullptr_t.
На ваши вопросы:
Почему namespace_const_message и const_message недоступны во время компиляции и, таким образом, запрещены в функции шаблона печати?
Вот почему constexpr
существует. Они могут использоваться там, где им нужна оценка времени компиляции, поэтому доступны шаблонные аргументы.
Верно ли мое предположение о строковых литералах?
После аргументов есть примечание об этом праве:
Примечание. Строковый литерал (2.14.5) не удовлетворяет требованиям любой из этих категорий и, следовательно, не является допустимый шаблон-аргумент.