使用命名空间中的模板调用模板模板方法时出现 False clang 错误

False clang error when calling a template template method with a template that is in a namespace

我有一个模板模板方法,当使用不在命名空间中的模板调用它时,它工作正常。但是,当使用命名空间中的模板调用它时,出现 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<class T, class Allocator=std::allocator<T>>
class vector;

注意它需要 2 个参数。

templates that take 2 parameters can match template<class>class if the 2nd one is defaulted; in 这不是真的。

至于 , they found a bug in the standard 中的 clang,如果您实现此功能:(通过上面评论中的@cpplearner)

(10): Despite being the resolution to a Defect Report, this feature is disabled by default in all language versions, and can be enabled explicitly with the flag -frelaxed-template-template-args in Clang 4 onwards. The change to the standard lacks a corresponding change for template partial ordering, resulting in ambiguity errors for reasonable and previously-valid code. This issue is expected to be rectified soon.

这可能有效:

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

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

What changed in C++17 to allow this, and is it a bug that clang produces an error?

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

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

自 C++17 起(CWG 150), the default template arguments are allowed for a 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