C++ 17可以处理嵌套的可变参数模板吗?

Sum*_*ood 6 c++ variadic-templates c++17

考虑下面的C++ 17代码,该代码测试一组枚举值以查看该集合中是否包含另一个枚举值:

enum Flag { val1, val2, val3, val4, val5 };

template<Flag arg> struct Value {
    template<Flag... set> struct IsIn {
        static constexpr bool value =
            static_cast<bool>(((set == arg) || ...));
    };
};
Run Code Online (Sandbox Code Playgroud)

这按预期工作:

bool x = Value<val4>::IsIn<val1, val2, val5>::value;
// x == false

bool y = Value<val2>::IsIn<val3, val2>::value;
// y == true
Run Code Online (Sandbox Code Playgroud)

但是,我希望测试是否所有一组值都包含在另一个集合中,如下所示:

template<Flag... args> struct Values {
    template<Flag... set> struct AreIn {
        static constexpr bool value =
            static_cast<bool>((Value<args>::IsIn<set...>::value && ...));
    };
};
Run Code Online (Sandbox Code Playgroud)

以上内容不适用于GCC 7.3或Clang 5.0; 他们都给出了相当神秘的答案,这些答案几乎无法洞察问题.鉴于允许模板参数列表中的参数包扩展(只要模板支持扩展),我很难弄清楚为什么这不是合法的C++.

Chr*_*ing 6

您遇到了C++语法中最令人烦恼的问题之一:不可推断的依赖名称.

当你这样做Foo<Bar>::Baz<Quux>,因为Foo<Bar>是一个从属名称,你必须先放置template关键字Baz,以防止解析器在悬崖上运行.Clang 通常非常擅长用一个有用的错误明确地告诉你这个,但在某些情况下(比如你的)它只是爆炸并且说Expected )或者同样无益的东西.

有关更多信息,请参阅此其他问题

因此,您需要做的就是修复模板,template在依赖模板调用上添加关键字:

template<Flag... args>
struct Values {
    template<Flag... set>
    struct AreIn {
        static constexpr bool value =
            static_cast<bool>((Value<args>::template IsIn<set...>::value && ...));
    };
};
Run Code Online (Sandbox Code Playgroud)

另请注意,这static_cast<bool>()是多余的.