Стандартная библиотека type_traits создает неожиданный результат с некоторыми псевдонимами типов, использующими decltype

#c #c 17 #typetraits

#c #c 17 #typetraits

Вопрос:

Позвольте мне проиллюстрировать. Давайте возьмем, например, std::is_same_v и std::is_base_of_v. Рассмотрим следующий код:

 #include <iostream>
#include <array>
#include <type_traits>

using namespace std;

struct base {};
struct derived : base { int foo; };

array<derived, 10> my_array;

int main()
{
    using c1 = decltype(*begin(my_array));
    using c2 = derived;

    if constexpr(is_same_v<c1,c2>)
    {
        cout<<"Correct!"<<endl;
    }
    else
    {
        cout << "No luck even though:" << endl
             << "c1 type is " << typeid(c1).name() << endl
             << "c2 type is " << typeid(c2).name() << endl;
    }

    if constexpr(is_base_of_v<base, c1>)
    {
        cout<<"Correct!"<<endl;
    }
    else
    {
        cout << "No luck even though:" << endl
             << "is_base_of_v<base, derived> = " << is_base_of_v<base, derived> << endl;
    }

    return 0;
}
 

Ожидаемый результат:

 Correct!
Correct!
 

Но фактический результат как в clang 10, так и в gcc 11:

 No luck even though:
c1 type is 7derived
c2 type is 7derived
No luck even though:
is_base_of_v<base, derived> = 1
 

Взорванный разум. В первую очередь меня интересует выяснить точную причину такого поведения, а затем, возможно, найти обходной путь. Если возможно, обходной путь должен работать с любым итеративным типом и только с std::array .

Комментарии:

1. Это было так. Пожалуйста, отправьте это как ответ, чтобы я пометил его как правильный. Меня сбило с толку то, что typeid сообщал о том же типе. Спасибо.

Ответ №1:

Ваша проблема в том, что у вас есть дополнительная ссылка:

 using c1 = decltype(*begin(my_array)); // derivedamp;
using c2 = derived;
 

is_same_v<derived, derivedamp;> равно false .

std::decay_t или std::remove_reference_t может помочь.

И typeid идентичны:

  1. Ссылается на объект std::type_info, представляющий тип type . Если type является ссылочным типом, результат ссылается на объект std::type_info, представляющий ссылочный тип.

Другой способ узнать тип — использовать этот трюк:

 template <typename> struct Debug; /*No definition*/

Debug<c1> d; // Incomplete type
 

с сообщением об ошибке, похожим на

ошибка: агрегат « Debug<derivedamp;> d имеет неполный тип и не может быть определен

ДЕМОНСТРАЦИЯ