考虑下面的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++.
关于模板消歧器的问题在这里给出:
在答案中我们可以读到:
ISO C++ 03 14.2/4
当成员模板专业化的名称出现之后.或 - >在postfix-expression中,或在qualified-id中的nested-name-specifier之后,postfix-expression或qualified-id显式依赖于template-parameter(14.6.2),成员模板名称必须是以关键字模板为前缀.否则,假定该名称命名非模板.
现在我来到这个我不太明白的例子:
template <class T>
class Base {
public:
template <int v>
static int baseGet() {return v;}
class InnerA {
public:
template <int v>
static int aget() {return v;}
};
class InnerB {
public:
typedef Base BaseType;
typedef BaseType::InnerA OtherType;
template <int v>
static int baseGet() {return BaseType::baseGet<v>();} //(A)
template <int v>
static int aget() {return OtherType::aget<v>();} //(B)
};
};
Run Code Online (Sandbox Code Playgroud)
它显然无法编译.你需要template在(B)行:OtherType::template aget<v>();.然而,g ++(4.4.3)和clang ++(2.9)都没有抱怨template线(A)缺乏.为什么?BaseType …