Gcc和clang似乎不同意这段代码是否应该编译:
#include <type_traits>
template <typename Signature, int N = 0>
struct MyDelegate { };
template <typename D>
struct signature_traits;
template <template <typename> class Delegate, typename Signature>
struct signature_traits<Delegate<Signature>>
{
using type = Signature;
};
static_assert(std::is_same_v<
void(int, int),
signature_traits<MyDelegate<void(int, int)>>::type
>);
见godbolt output here and try it。我在这里支持clang,但是C ++标准对此有何看法?
后续问题 - 这可以在clang中使用吗?
答案 0 :(得分:13)
这是完全有效的代码,gcc是对的。 &#34;功能&#34;是introduced in C++17。它不是一个真正的功能,因为它是一个缺陷报告。 MyDelegate
匹配signature_traits
的部分特化,因此应该正确地将其视为gcc。请注意,它的工作原理是因为第二个模板参数是默认的。
clang没有编译它的原因是因为缺陷报告有缺陷:P。它doesn't introduce the appropriate change in partial ordering,这不是很好,并使以前的有效代码再次模糊不清。
预计很快就会被修复,但与此同时,clang决定隐藏&#34;标志背后的功能,-frelaxed-template-template-args。
所以,只需启用该标志进行编译,你应该没问题。
答案 1 :(得分:0)
问题是MyDelegate
与template <typename> class
不匹配,因为接收两个模板参数:类型(Signature
)和 int
(N
)。
是:第二个具有默认值。但签名仍为template <typename, int> class
。
所以我认为g ++是错误的(编译没有错误)和clang ++是对的。 Rakete1111纠正了我(谢谢!):你的代码错误之前 C ++ 17但从C ++ 17开始是正确的(参见他对参考文献的回答)。所以(你正在编译C ++ 17)g ++是对的,而clang ++是错误的。
可能的解决方案(等待正确的clang ++)定义signature_traits
如下
template <template <typename, int=0> class Delegate, typename Signature>
struct signature_traits<Delegate<Signature>>
{
using type = Signature;
};
或者,更好的恕我直言,添加整数参数
template <template <typename, int> class Delegate, typename Signature, int N>
struct signature_traits<Delegate<Signature, N>>
{
using type = Signature;
};
观察两种解决方案都与
兼容static_assert(std::is_same<
void(int, int),
typename signature_traits<MyDelegate<void(int, int)>>::type
>::value);