(Извините, я только что заметил, что этот вопрос помечен как c
, а не c++
. Возможно, мой ответ в конце концов не имеет отношения к этому вопросу!)
Строковые литералы не совсем const
или not-const
, есть специальное странное правило для литералов.
( Сводка : Литералы могут быть взяты по ссылке на массив как foo( const char (&)[N])
и не могут быть приняты как неконстантный массив. Они предпочитают распадаться до const char *
. Пока что создается впечатление, что они const
. Но существует специальное устаревшее правило, которое позволяет литералам уменьшаться до char *
. См. Эксперименты ниже.)
(После экспериментов, проведенных на clang3.3 с -std=gnu++0x
. Возможно, это проблема C ++ 11? Или специфическая для clang? В любом случае происходит что-то странное.)
Сначала литералы выглядят как const
:
void foo( const char * ) { std::cout << "const char *" << std::endl; }
void foo( char * ) { std::cout << " char *" << std::endl; }
int main() {
const char arr_cc[3] = "hi";
char arr_c[3] = "hi";
foo(arr_cc); // const char *
foo(arr_c); // char *
foo("hi"); // const char *
}
Два массива ведут себя как положено, демонстрируя, что foo
может сказать нам, является ли указатель const
или нет. Затем "hi"
выбирает const
версию foo
. Так что, похоже, все решено: литералы const
... не так ли?
Но , если вы удалите void foo( const char * )
, тогда это становится странным. Во-первых, вызов foo(arr_c)
завершается с ошибкой во время компиляции. Это ожидается. Но буквальный вызов (foo("hi")
) работает через неконстантный вызов.
Итак, литералы "более постоянны", чем arr_c
(потому что они предпочитают распадаться до const char *
, в отличие от arr_c
. Но литералы "менее постоянны", чем arr_cc
, потому что они готовы распадаться на char *
при необходимости.
(Clang выдает предупреждение при затухании до char *
).
Но как насчет распада? Давайте избегать этого для простоты.
Давайте вместо этого возьмем массивы по ссылке в foo. Это дает нам более «интуитивные» результаты:
void foo( const char (&)[3] ) { std::cout << "const char (&)[3]" << std::endl; }
void foo( char (&)[3] ) { std::cout << " char (&)[3]" << std::endl; }
Как и раньше, литерал и массив const (arr_cc
) используют версию const, а неконстантная версия используется arr_c
. И если мы удалим foo( const char (&)[3] )
, то получим ошибки как foo(arr_cc);
, так и foo("hi");
. Короче говоря, если мы избегаем распада указателя и вместо этого используем ссылку на массив, литералы ведут себя так, как если бы они были const
.
Шаблоны
В шаблонах система будет выводить const char *
вместо char *
, и вы "застряли" с этим.
template<typename T>
void bar(T *t) { // will deduce const char when a literal is supplied
foo(t);
}
Таким образом, в основном, литерал ведет себя как const
всегда, за исключением особого случая, когда вы напрямую инициализируете char *
литералом.