C++ 中允许模板模板参数的什么“转换”?

时间:2021-04-24 02:50:11

标签: c++ g++ language-lawyer clang++ template-templates

我试图了解在什么情况下我可以将类型模板作为具有不同签名的模板模板参数的参数传递。例如,我希望以下内容可以成功编译。

template <typename...>
struct foo { };

template <template <typename> typename Template>
struct bar { };

using quux = bar<foo>;

毕竟,bar 要求的模板只接受一种类型的模板参数,而我给了它一个。但是对于 Clang 11.0.1,这不能编译。

好的,好的。当然,如果这是不允许的,那么以下内容也应该被禁止。

template <typename>
struct foo { };

template <template <typename...> typename Template>
struct bar { };

using quux = bar<foo>;

这里的 bar 要求一个可以接受任意数量类型模板参数的模板,我给它一个。然而 Clang 接受了这一点! (当然,如果我在 bar 中编写代码来实例化 Template,模板参数与 foo 的签名不匹配,它仍然会失败。)

这在我看来是倒退的。它允许将更具体的模板签名转换为更通用的签名,而不是相反。

我也尝试过使用 GCC 10.2.0。 GCC 接受两者。哈哈。

我正在使用 -Wall -Wextra -O0 -std=c++20 -pedantic 与两个编译器一起编译。

标准是否真的没有说明上面的第一个例子是否格式错误,或者至少有一个编译器不符合标准?

而且,无论标准要求什么,为什么 Clang 会在这里做出选择?这对我来说似乎是一个错误。

1 个答案:

答案 0 :(得分:3)

我认为 Clang 是错误的。由于 C++17 (P0522R0, CWG 150),采用 foo 之类的参数包的模板,应该允许将 bar 指定为 template template argument,即使它需要一个模板参数。

<块引用>
template<class T> class A { /* ... */ };
template<class T, class U = T> class B { /* ... */ };
template <class ...Types> class C { /* ... */ };

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
X<C> xc; // OK in C++17 after CWG 150
         // Error earlier: not an exact match