Вот еще один способ различения строкового литерала и указателя, основанный на том факте, что строковые литералы имеют тип массива, а не тип указателя:
#include <iostream>
void foo(char *msg)
{
std::cout << "non-const char*\n";
}
void foo(const char *&msg) // & needed, else this is preferred to the
// template function for a string literal
{
std::cout << "const char*\n";
}
template <int N>
void foo(const char (&msg)[N])
{
std::cout << "const char array reference ["<< N << "]\n";
}
int main() {
foo("bar"); // const char array reference [4]
}
Но обратите внимание, что все они (включая исходный)функцию) можно «обмануть», передав что-то, что не является строковым литералом:
const char *soap = 0;
foo(soap);
char *b = 0;
foo(b);
const char a[4] = {};
foo(a);
В C ++ нет типа, который был бы уникальным для строковых литералов.Таким образом, вы можете использовать тип, чтобы указать разницу между массивом и указателем, но не узнать разницу между строковым литералом и другим массивом.RTTI бесполезен, потому что RTTI существует только для классов с хотя бы одной виртуальной функцией-членом.Все остальное зависит от реализации: в стандарте нет гарантии, что строковые литералы будут занимать какую-либо конкретную область памяти или что один и тот же строковый литерал, использованный дважды в программе (или даже в модуле компиляции), будет иметь один и тот же адрес.С точки зрения места хранения, все, что реализация может делать со строковыми литералами, разрешено также делать с моим массивом a
.