MS Visual Studio 2017 上的 Variadic 模板编译问题

Variadic template compilation issue on MS Visual Studio 2017

我需要一个模板来找出 class 从其基类及其索引继承的类型顺序。该代码适用于 clang 和 gcc,但在目标环境 Visual Studio 中,我收到内部编译器错误 "fatal error C1001: An internal error has occurred in the compiler."。我正在寻找一些解决方法或者可能是我的代码中的错误。是的,我已经试过了 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;
}

I'm getting an internal compiler error "fatal error C1001: An internal error has occurred in the compiler.".

所以,我想,你的代码是正确的,但编译器有问题。

I'm looking for some workaround or maybe an error in my code.

我没有你的编译器,所以这是在黑暗中拍摄,但我建议使用另一个专业化(U 和 [=13= 的专业化)重写你的 find_type 结构] 是同一类型;UT 的特化不同)并从 std::integral_constant.

继承 value

所以我提出以下建议

   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...>
    { };

内部编译器错误始终是编译器中的错误,无论是否存在 你的代码有什么问题吗?要解决这个问题,您可以替换:

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 为空时。

Live demo

另一种可能的替代方法是通过模板函数,而不是 find_type 结构。

举个例子...如果你定义一个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;
    }