std :: is_same не работает через decltype автоматической переменной constexpr - PullRequest
2 голосов
/ 20 марта 2019

Я пытался static_assert, чтобы какой-то алгоритм метапреобразователя работал, и он невероятно не сравнивался с тем же, хотя typeid().name() возвращал точно такую ​​же строку.

Повторение выражения типав typedef можно исправить is_same, но Я не могу понять, как повторение выражения инициализатора в typedef меняет тип по сравнению с принятием decltype автоматической переменной, инициализированной тем же выражением .

Более конкретное объяснение того, что я делал:
Я сделал мета-преобразователь, который может преобразовать список мета-значений (содержащий перечислители) в кортеж std :: tup всех перечислителей.Затем я проверил, что сгенерированный кортеж - тот, который я ожидал.

весь код ниже, проверьте строку с комментариями // работает // не работает
И последний тест в конце.

#include <type_traits>
#include <tuple>

template<typename T> struct ValueListAsTuple;  // master template
// destructurer of list:
template<template <auto...> class L, auto... Vs>
struct ValueListAsTuple<L<Vs...>>
{
    static constexpr auto value = std::make_tuple(Vs...);
    //using type = decltype(std::make_tuple(Vs...)); // works
    using type = decltype(value); // doesn't work
};

// template typedef
template<typename T> using ValueListAsTuple_t = typename ValueListAsTuple<T>::type;

struct Kind
{
    enum EnumType { E1, E2 };
    template <auto... Values> struct MetaVals{};  // meta value list
    using MetaValueList = MetaVals<
        E1,
        E2
    >;
};

int main(int argc, const char* argv[])
{
    auto tuple = ValueListAsTuple_t< Kind::MetaValueList > {};

    //std::cout << typeid(tuple).name() << '\n';
    // this prints: "class std::tuple<enum Kind::EnumType, enum Kind::EnumType>"

    // manual re-creation of the type, for testing:
    std::tuple< Kind::EnumType, Kind::EnumType > t2;

    //std::cout << typeid(t2).name() << '\n';
    // this prints the exact same thing.

    static_assert( std::is_same_v< std::tuple_element<0, decltype(tuple)>::type, Kind::EnumType > );
    static_assert( std::is_same_v< std::tuple_element<1, decltype(tuple)>::type, Kind::EnumType > );

    // WHAT ???
    static_assert( std::is_same_v< 
                        ValueListAsTuple_t< Kind::MetaValueList >,
                        std::tuple< Kind::EnumType, Kind::EnumType >
                                 > );
    // is_convertible_v works but I don't care ! wth ?
}

Итак, как вы можете видеть, is_same не мог вывести тот же тип, когда type был объявлен через value, но он работал, если я повторю std::make_tuple(...Я не вижу, где есть разница между этими двумя формами.

Я даже проверил элемент за элементом, что типы одинаковы в каждом индексе кортежа.

Проверьте это в действиив Godbolt:
https://godbolt.org/z/QUCXMB

Поведение одинаково для gcc / clang / msvc

1 Ответ

5 голосов
/ 20 марта 2019

На самом деле это тривиальная ошибка, но, к сожалению, ее трудно обнаружить.Проблема, с которой вы сталкиваетесь, заключается в том, что constexpr подразумевает const.Таким образом, в вашем примере type - это const tuple<...>, который отличается от типа, который вы не проверяете cv.Короткое исправление псевдонима должно сделать ваш тест успешным:

using type = std::remove_const_t<decltype(value)>;
...