Подтвердить что ты не робот

Некоторые 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?
  • Мое предположение о правильности строковых литералов?

Спасибо.

4b9b3361

Ответ 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) не удовлетворяет требованиям любой из этих категорий и, следовательно, не является допустимый шаблон-аргумент.