模板-模板参数推导:三个不同的编译器三种不同的行为
template template parameter deduction: three different compilers three different behaviors
考虑下面的演示程序。
#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中的第一种情况。我已经在开发者社区提交了一个问题。
相关文章:
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 我可以使用 g++ 进行三种比较 (<=>) 吗?
- 多维数组存储三种不同的数据类型?
- 如何使一个函数具有三种不同的输出条件?
- 输出一个数字,该数字可能是三种类型之一
- 如何创建一个包含三种不同类型的向量的向量
- 当一种方法有三种返回可能性时该怎么办?
- 三种类型之间的隐式转换交互
- 可以使用 std::p air 保存三种数据类型的向量
- 解释C 中三种返回类型的方法
- 如何使用“英特尔C++编译器”(ICC)在三种方法上使用SFINAE
- 加载动态链接库的第三种方法?大头针
- 如何以及何时使用(或不使用)三种特定情况的例外
- 我使用三种内存清除变体.他们都安全吗?我可以得到内存泄漏吗?
- 在给定前景色和背景色的情况下,我如何计算第三种颜色
- 如何使用条件运算符表达三种情况
- 为什么这个为三种整数类型重载的函数无法编译?
- 创建一个有三种方法可供选择的加密程序!它有问题,我不知道如何解决
- 三种显式上转换到私有基类的区别
- 调用方法的这三种语法形式之间有什么区别?