Проблема компиляции шаблона Variadic в MS Visual Studio 2017 - PullRequest
0 голосов
/ 04 декабря 2018

Мне нужен шаблон, чтобы узнать порядок типов, в которых класс наследует свои базы и их индекс.Код прекрасно работает с clang и gcc, но в Visual Studio, которая является целевой средой, я получаю внутреннюю ошибку компилятора «фатальная ошибка C1001: в компиляторе произошла внутренняя ошибка».Я ищу обходной путь или, возможно, ошибку в моем коде.Да, я уже попробовал Google.

Спасибо, заранее.

#include <type_traits>
#include <iostream>

struct BaseA
{
};

struct BaseB
{
};

struct BaseC
{
};

template <class... Types>
class type_list {};

template<typename Type, typename TypeList>
struct get_idx_for_type;

template<typename Type, template<typename...> typename TypeList, typename ...Types>
struct get_idx_for_type<Type, TypeList<Types...>>
{
    template<int I, typename T, typename ...Rest>
    struct find_type;

    template<int I, typename T, typename U, typename ...Rest>
    struct find_type< I, T, U, Rest... >
    {
        // problematic line for compiler, problem is somewhere in find_type recursion
        static constexpr int value = std::is_same<T, U>::value ? I : find_type<I + 1, T, Rest...>::value;
    };

    template<int I, typename T, typename U>
    struct find_type< I, T, U >
    {
        static constexpr int value = std::is_same<T, U>::value ? I : -1;
    };

    static constexpr int value = find_type<0, Type, Types...>::value;
};

template<typename ...Bases>
struct Foo : public Bases...
{
    using base_types_list = type_list<Bases...>;
};

int main()
{
    using T = Foo<BaseA, BaseB, BaseC>;
    Foo<BaseA, BaseB, BaseC> q;

    int a = get_idx_for_type<BaseA, T::base_types_list>::value;

    std::cout << a << std::endl;

    return 0;
}

Ответы [ 3 ]

0 голосов
/ 04 декабря 2018

Внутренняя ошибка компилятора - это всегда ошибка компилятора, независимо от того, есть ли что-то не так с вашим кодом.Чтобы обойти это, вы можете заменить:

template<int I, typename T, typename U, typename ...Rest>
struct find_type< I, T, U, Rest... >
{
    // problematic line for compiler, problem is somewhere in find_type recursion
    static constexpr int value = std::is_same<T, U>::value ? I : find_type<I + 1, T, Rest...>::value;
};

на:

template<int I, typename T, typename U, typename V, typename ...Rest>
struct find_type< I, T, U, V, Rest... >
{
    static constexpr int value = std::is_same<T, U>::value ? I : find_type<I + 1, T, V, Rest...>::value;
};

, чтобы помочь VC ++ в устранении неоднозначности:

template<int I, typename T, typename U>
struct find_type< I, T, U >
{
    static constexpr int value = std::is_same<T, U>::value ? I : -1;
};

, когда ...Rest пусто.

Живая демоверсия

0 голосов
/ 04 декабря 2018

Другой возможной альтернативой является передача через шаблонную функцию вместо find_type struct.

В качестве примера ... если вы определите static constexpr метод find_type_func() следующим образом (C ++ 17, но я могу легко адаптировать его к C ++ 14, если хотите)

   template <typename T, typename ... List>
   constexpr static int find_type_func ()
    {
      int ret { -1 };
      int i   { 0 };

      ((ret = (ret == -1) && std::is_same<T, List>{} ? i : ret, ++i), ...);

      return ret;
    }

вы можете удалить struct find_type и инициализировать value следующим образом

static constexpr int value = find_type_func<Type, Types...>();

- РЕДАКТИРОВАТЬ -

Как и просили, версия C ++ 14

   template <typename T, typename ... List>
   constexpr static int find_type_func ()
    {
      using unused = int[];

      int ret { -1 };
      int i   { 0 };

      (void)unused { 0, (std::is_same<T, List>::value ? ret = i : ++i)... };

      return ret;
    }
0 голосов
/ 04 декабря 2018

Я получаю внутреннюю ошибку компилятора "Неустранимая ошибка C1001: Внутренняя ошибка произошла в компиляторе.".

Итак, я полагаю, ваш код правильный, ноошибка компилятора.

Я ищу обходной путь или, возможно, ошибку в моем коде.

У меня нет вашего компилятора, так что это выстрелтемный, но я предлагаю переписать вашу find_type структуру, используя другую специализацию (специализация для U и T одного типа; специализация для U и T различна) и наследовать value из std::integral_constant.

Поэтому я предлагаю следующее

   template <int, typename ...>
   struct find_type;

   template <int I, typename T>
   struct find_type<I, T> : public std::integral_constant<int, -1>
    { };

   template <int I, typename T, typename ... Rest>
   struct find_type<I, T, T, Rest...> : public std::integral_constant<int, I>
    { };

   template <int I, typename T, typename U, typename ... Rest>
   struct find_type<I, T, U, Rest...> : public find_type<I+1, T, Rest...>
    { };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...