模板-模板参数推导:三个不同的编译器三种不同的行为

template template parameter deduction: three different compilers three different behaviors

本文关键字:编译器 三种 三个 参数 模板      更新时间:2023-10-16

考虑下面的演示程序。

#include <iostream>
template <class T1, class T2 = T1>
struct A 
{
};
template <template <class> class T>
void f( const T<int> & )
{
std::cout << "f( const T<int> & )n";
}
int main()
{
A<int> a;
f( a );
f<A>( a );
}

编译器gcc HEAD 10.0.1 20200成功编译程序,程序输出为

f( const T<int> & )
f( const T<int> & )

编译器clang HEAD 11.0.0既不编译函数f的第一个调用,也不编译函数f的第二个调用。它会发出类似的错误消息

prog.cc:25:5: error: no matching function for call to 'f'
f( a );
^
prog.cc:9:6: note: candidate template ignored: substitution failure: template template argument has different template parameters than its corresponding template template parameter
void f( const T<int> & )
^
1 error generated.

编译器Visual C++2019不编译第一个函数调用

f( a );

但成功编译了第二个函数调用

f<A>( a );

那么问题来了,哪个编译器的行为符合C++17(或者可能是C++20(标准?

这是CWG 150,由C++17中的DR P0522解决。

注意,g++在C++14模式(-std=c++14等(中拒绝程序(两个调用都是f(。

Clang仅在非默认模式下接受您的程序,并根据以下原理使用标志-frelaxed-template-template-args启用:

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

我不确定Clang到底关心的是哪些歧义错误,但一个合理的例子是最近的这个问题。

对于MSVC,它在C++14模式下拒绝了对f的第二次调用(-std:c++14(,在C++17模式下接受了它(-std:c++17(,表明他们认为根据合规性表,第二次呼叫被P0522覆盖;不幸的是,他们似乎没有考虑到第一次调用的情况,在第一次调用中,模板模板参数是从函数参数推导出来的,这相当于CWG150中的第一种情况。我已经在开发者社区提交了一个问题。