template <typename Foo, Foo Part>
struct TSelect {};
enum What {
The
};
template <typename Foo>
struct AnotherOneSelector {
static constexpr Foo Id = Foo::The;
};
template <typename Foo, typename SelectPartType>
struct THelper;
template <typename Foo>
struct THelper<Foo, TSelect<Foo, AnotherOneSelector<Foo>::Id>> {};
template <typename Foo, Foo PartId>
struct THelper<Foo, TSelect<Foo, PartId>> {};
int main() {
THelper<What, TSelect<What, What::The>> t;
}
此代码使用gcc8.1以及每个标准选项(c ++ 11,c ++ 14,c ++ 17)进行编译,但是clang干线不使用c++17(尽管使用{{3 }}一切都很好)。
消息错误是:
test.cpp:23:49: error: ambiguous partial specializations of 'THelper<What, TSelect<What, The> >'
THelper<What, TSelect<What, What::The>> t;
^
test.cpp:17:12: note: partial specialization matches [with Foo = What]
struct THelper<Foo, TSelect<Foo, AnotherOneSelector<Foo>::Id>> {};
^
test.cpp:20:12: note: partial specialization matches [with Foo = What, PartId = The]
struct THelper<Foo, TSelect<Foo, PartId>> {};
^
1 error generated.
哪个编译器正确?我没有看到模板的任何变化 C ++ 17专业化。
答案 0 :(得分:5)
此处的C ++ 17区别在于,您可以从相应的参数推导出非类型参数的类型。 Clang显然在做推论错误。
与此处相关,您应该为Foo
综合一个唯一类型,并尝试针对Foo
推导PartId
中的THelper<Foo, TSelect<Foo, PartId>>
和THelper<Unique, TSelect<Unique, AnotherOneSelector<Unique>::Id>>
。似乎正在发生的事情是Clang认为AnotherOneSelector<Unique>::Id
具有一些单独的唯一类型-称为Unique2
-,因此在C ++ 17中推论失败,因为您推导了Foo
的冲突类型。众所周知,对这样的非推导上下文的处理未得到充分指定,但是我敢肯定,这是要使用转换后的模板参数的类型而不是原始参数来推导。
两个可能的解决方法是:
Foo
的推断。例如:template <typename Foo, std::remove_const_t<Foo> PartId>
。Foo
以避免虚假冲突:struct THelper<Foo, TSelect<Foo, Foo{AnotherOneSelector<Foo>::Id}>>