【问题标题】:Deducing first template argument with other template parameters defaulted推导第一个模板参数与默认的其他模板参数
【发布时间】:2018-07-04 22:40:21
【问题描述】:

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 中使用吗?

【问题讨论】:

    标签: c++ templates language-lawyer template-meta-programming c++17


    【解决方案1】:

    这是完全有效的代码,gcc 是正确的。 “功能”是introduced in C++17。这不是一个真正的功能,因为它是一个缺陷报告。 MyDelegate 匹配 signature_traits 的部分特化,因此应该像 gcc 一样正确对待它。请注意,它之所以有效,是因为第二个模板参数是默认的。

    clang 不编译它的原因是该缺陷报告有一个缺陷:P。它doesn't introduce the appropriate change in partial ordering,这不是很好,并且使以前的有效代码再次模棱两可。

    预计很快就会修复,但与此同时,clang 决定将功能“隐藏”在标志后面,-frelaxed-template-template-args。

    所以,只需在启用该标志的情况下进行编译,就可以了。

    【讨论】:

      【解决方案2】:

      问题是MyDelegate 不匹配template &lt;typename&gt; class 因为接收两个模板参数:一个类型(Signature)和一个int( N)。

      是:第二个有默认值。但是签名仍然是template &lt;typename, int&gt; 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);
      

      【讨论】:

      • 其实gcc是对的。见P0522
      • @Rakete1111 - 你(和 g++)是对的;我根本不知道 C++17 的这些改进。谢谢。
      • 你们可能想要使用编译器。拥有开发团队的人不会太挑剔而无法遵守世界公认的标准。我对 clang 感到非常生气,因为我去年写了大约 150 000 行大量模板,只要 GCC 可用,它们就可以在每个系统上完美编译。我真的必须为我的代码制作一个“解释为智障”的版本吗?
      • @GézaTörök - 抱歉,我不明白您评论的意思。你说我和Rakete1111不使用编译器?这里我们有一个关于 C++ 代码示例的问题。 C++ 是一门复杂的语言,非常复杂。有时真的很难理解一段代码是否与语言兼容。有时 g++ 和 clang++ 在某些极端情况下存在分歧(请参阅我的问题以获取一些示例),有时 g++ 是正确的,有时 clang++ 是正确的。我试图提出一个替代方案来与这两个编译器一起工作。这是错的吗?这让我成为了一个糟糕的程序员?
      • @max66 如果您对我的评论感到不快,我很抱歉,这根本不是我的本意。我没有批评您或任何人的编程技能或争论 C++ 的复杂性,我也没有任何理由这样做。我只是在抱怨 clang 的不合规性,这导致我这周加班了 100 小时,这在某种程度上表明了 GCC 的 巨大 优势。对于随之而来的愤怒,我深表歉意。
      猜你喜欢
      • 2012-11-18
      • 1970-01-01
      • 1970-01-01
      • 2023-01-24
      • 1970-01-01
      • 1970-01-01
      • 2021-05-23
      • 2014-11-06
      • 2012-08-07
      相关资源
      最近更新 更多