typeid ("")! = typeid (const char *) - PullRequest
       25

typeid ("")! = typeid (const char *)

14 голосов
/ 12 июня 2019

Я делаю библиотеку C ++, которая в значительной степени опирается на RTTI (настраиваемый мост на другой язык) и очень смущена типом строкового литерала.

Это простой тест, который я сделал, чтобы показать проблему:

std::cout << typeid(const char*).name() << std::endl; // PKc
std::cout << std::any("").type().name() << std::endl; // PKc
std::cout << typeid("").name() << std::endl;          // A1_c

Для меня это выглядит как первые два типа печати для const char*, но последний является массивом.

Почему результаты для std::any("").type() и typeid("") отличаются? Есть ли способ получить первое поведение, то есть сделать результаты для строковых литералов непротиворечивыми (я использую идентификацию типа для вызова различных обработчиков типов)?

P.S .: тесты выполняются с использованием Clang версии 8.0.0-3 (tags / RELEASE_800 / final) в Ubuntu 19.04.

Ответы [ 3 ]

17 голосов
/ 12 июня 2019

Как уже упоминалось, тип строкового литерала "" равен const char[1], как объясняется, например, Каков тип данных строкового литерала в C ++? .

Тип, сохраненный в std::any(""), равен const char*, потому что вы используете следующий конструктор (http://www.eel.is/c++draft/any.cons#8):

// Effects: Constructs an object of type any that contains an object of 
// type std::decay_t<T> direct-initialized with std::forward<T>(value).
template< class T>
any( T&& value );

В этом случае T равно const char(&)[1] (тип строкового литерала ""), и поэтому std::decay_t<const char(&)[1]> даст вам const char*, поэтому typeid() из std::any("").type() является идентификатором типа const char*.

4 голосов
/ 12 июня 2019

Почему результаты для std::any("").type() и typeid("") отличаются?

Согласно следующей ссылке :

template< class ValueType >
any( ValueType&& value );

4) Создает объект с начальным содержимым объект типа std::decay_t<ValueType>, с прямой инициализацией из std::forward<ValueType>(value).

std::decay_t<const char[1]> - это const char*.


Вот цитата из FrankHB1989 на форуме isocpp.org , которая, на мой взгляд, важна для понимания std::any в контексте этого вопроса:

[std::any] даже не для "любого объекта". Как я уже говорил ранее, я ожидал, что слово «any» будет сокращенным для «любого типа объекта первого класса» (то есть cv-неквалифицированный тип объекта без массива), но std::any имеет дополнительное уточнение CopyConstructible для типа значения так что это фактически для "любого копируемого cv-неквалифицированного типа объекта без массива" вместо этого.

Как таковой

Есть ли способ получить первое поведение, то есть сделать результаты для строковых литералов непротиворечивыми (я использую идентификацию типов для вызова различных обработчиков типов)?

Нет способа иметь std::any массива (вы можете иметь std::any из std::array, но строковый литерал не является std::array), и нет способа заставить typeid("") быть указателем , Однако вы можете использовать std::decay_t<decltype("")>, чтобы получить тот же тип, который хранится в std::any.

2 голосов
/ 12 июня 2019

Распространено заблуждение, что строковый литерал имеет тип const char*.

Это не так. Он имеет тип const char[<size + 1>] (плюс один для нулевого терминатора).

например. "" имеет тип const char[1].

Но мы часто присваиваем строковый литерал для const char* вне соглашения (а также потому, что в противном случае мы запускаем специальные правила, которые приводят к копированию строки).

Кроме того, из-за правил распада имени массива довольно трудно наблюдать за массивностью имени в C (и, соответственно, в C ++); то, что std::any работает так, как оно есть, является примером этого.

...