C ++ 17中Clang的歧义局部专业化 [英] Ambiguous partial specializations with Clang in C++17

查看:151
本文介绍了C ++ 17中Clang的歧义局部专业化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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 (尽管使用 c ++ 14 一切都很好)。

This code compiles with gcc8.1 with each of the standard option (c++11, c++14, c++17), but clang trunk does not with c++17 (although with c++14 everything is fine).

消息错误是:

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中看到模板
专业化方面的任何更改。

Which compiler is correct? I haven't seen any changes in template specialization in C++17.

推荐答案

C ++ 17此处的区别在于,您可以从相应的参数推导出非类型参数的类型。而且Clang显然在做推论错误。

The C++17 difference here is that you can deduce the type of a non-type parameter from the corresponding argument. And Clang is apparently doing the deduction wrong.

与此相关,您应该为 Foo 合成一个唯一的类型,并尝试推导<$ c在 THelper< Foo,TSelect< Foo,PartId>>> Foo PartId c>反对 THelper< Unique,TSelect< Unique,AnotherOneSelector< Unique> :: Id>> 。似乎正在发生的事情是Clang将 AnotherOneSelector< Unique> :: Id 视为具有一些单独的唯一类型-称为 Unique2 -,使得推论在C ++ 17中失败,因为您推导了 Foo 的类型冲突。众所周知,对这样的非推导上下文的处理未得到充分指定,但是我敢肯定,这是要使用转换后的模板参数的类型而不是原始类型来推论。

As relevant here, you are supposed to synthesize a unique type for Foo and try to deduce the Foo and PartId in THelper<Foo, TSelect<Foo, PartId>> against THelper<Unique, TSelect<Unique, AnotherOneSelector<Unique>::Id>>. What seems to be happening is that Clang treats AnotherOneSelector<Unique>::Id to have some separate unique type - call it Unique2- so that the deduction fails in C++17 because you deduced conflicting types for Foo. The handling of non-deduced contexts like this is notoriously underspecified, but I'm pretty sure it's meant to deduce using the converted template argument's type rather than the original.

两个可能的解决方法是:

Two possible workarounds are:


  • 禁止从非类型参数中减去 Foo 将类型包装到非推断上下文中。例如: template< typename Foo,std :: remove_const_t< Foo> PartId>

  • 在模板参数中强制转换为 Foo 以避免虚假冲突: struct THelper< Foo,TSelect< Foo,Foo {AnotherOneSelector< Foo> :: Id}>>>

  • Suppress deduction of Foo from the non-type argument by wrapping the type into a non-deduced context. For example: template <typename Foo, std::remove_const_t<Foo> PartId>.
  • Force the conversion to Foo in the template argument to avoid the spurious conflict: struct THelper<Foo, TSelect<Foo, Foo{AnotherOneSelector<Foo>::Id}>>

这篇关于C ++ 17中Clang的歧义局部专业化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆