【问题标题】:False clang error when calling a template template method with a template that is in a namespace使用命名空间中的模板调用模板模板方法时出现错误的 clang 错误
【发布时间】:2018-08-07 10:07:01
【问题描述】:

我有一个模板模板方法,当使用不在命名空间中的模板调用它时,它可以正常工作。但是,当使用命名空间中的模板调用它时,我会收到一个 clang 错误。 MSVC 和 gcc 编译没有问题,但只有当我将标准设置为 C++17 时。

这是一个最小的例子

#include <vector>

template<template<typename> typename Template>
Template<int> foo() {
    return {};
}

template <typename T>
using my_vector = std::vector<T>;

int main()
{
    foo<my_vector>(); // compiles
    foo<std::vector>(); // does not compile in clang or without C++17
}

Here is a live example.

没有C++17的gcc错误是:

<source>:14:5: error: no matching function for call to 'foo'

clang 错误是:

<source>:14:22: error: no matching function for call to 'foo<template<class _Tp, class _Alloc> class std::vector>()'
<source>:4:15: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'Template'

C++17 中发生了哪些变化以允许这样做,它是 clang 产生错误的错误吗?

【问题讨论】:

  • 恕我直言,命名模板类型参数Template 是一个值得商榷的选择:)
  • P0522R0。请参阅clang.llvm.org/cxx_status.html#p0522 了解 clang 禁用此功能的原因。
  • @lubgr 是的,我知道,我只是想在这个例子中它可能清楚我的意思:)

标签: c++ templates c++17 clang++


【解决方案1】:

向量是

template<class T, class Allocator=std::allocator<T>>
class vector;

注意它需要 2 个参数。

模板中,如果默认第二个参数,则带有两个参数的模板可以匹配template&lt;class&gt;class;在 这不是真的。

至于中的clang,如果你实现了这个功能,他们found a bug in the standard:(通过上面cmets中的@cpplearner)

(10):尽管是缺陷报告的解决方案,但在所有语言版本中默认禁用此功能,并且可以在 Clang 4 及更高版本中使用标志 -frelaxed-template-template-args 显式启用。对标准的更改缺少模板偏序的相应更改,导致合理且先前有效的代码出现歧义错误。预计此问题将很快得到纠正。

这可能有效:

template<template<class...> class Z>
Z<int> foo() {
  return {};
}

因为有规则让class... 匹配任意数量的参数。

【讨论】:

  • 该死的,我忘了std容器类有更多的模板参数。你是对的。这有效: template
  • 另一种选择是使用标志-frelaxed-template-template-args,但这当然可能会在将来导致错误。
【解决方案2】:

C++17 中发生了哪些变化以允许这样做,它是 clang 产生错误的错误吗?

是的,自 C++17 以来行为发生了变化,Clang 似乎不符合标准。

注意std::vector有2个模板参数(第2个有默认值),而模板模板参数Template只需要一个。他们不匹配。

自 C++17 (CWG 150) 起,template template argument 允许使用默认模板参数来匹配具有较少模板参数的模板模板参数。

template<class T> class A { /* ... */ };
template<class T, class U = T> class B { /* ... */ };

template<template<class> class P> class X { /* ... */ };
X<A> xa; // OK
X<B> xb; // OK in C++17 after CWG 150
         // Error earlier: not an exact match

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-04
    • 2013-08-31
    • 1970-01-01
    相关资源
    最近更新 更多