rub*_*nvb 17 c++ initializer-list overload-resolution c++11
当我发现下面的代码输出"指针"时,我遇到了真实的WTF时刻.
#include <iostream>
#include <utility>
template<typename T>
struct bla
{
static void f(const T*) { std::cout << "pointer\n"; }
static void f(const T&) { std::cout << "reference\n"; }
};
int main()
{
bla<std::pair<int,int>>::f({});
}
Run Code Online (Sandbox Code Playgroud)
将std::pair<int,int>模板参数更改为int或任何其他基本类型,给(至少对我来说)预期的"模糊过载"错误.似乎内置类型在这里是特殊的,因为任何用户定义的类型(聚合,非平凡,具有默认构造函数等)都会导致调用指针超载.我相信模板不是重现它的必要条件,它只是让尝试不同类型变得简单.
就个人而言,我不认为这是合乎逻辑的,我认为在所有情况下都会出现模糊的重载错误,无论模板参数如何.GCC和Clang(我相信MSVC)在C++ 11/14/1z中都不同意我的观点.注意我完全知道这两个重载存在的错误API ,我保证不会写这样的东西.
所以问题就变成了:发生了什么?
小智 5
哦,这很讨厌.
Per [over.ics.list] p4和p7:
4否则,如果参数是非聚合类,
X并且每个13.3.1.7的重载决策选择一个最佳构造函数X来X从参数初始化列表中执行类型对象的初始化,则隐式转换序列是用户定义的转换序列与第二标准转换序列进行同一性转换.[...][...]
6否则,如果参数是参考,请参见13.3.3.1.4.[ 注意:本节中的规则适用于初始化参考的基础临时值.- 尾注 ] [...]
[...]
7否则,如果参数类型不是类:
[...]
(7.2) - 如果初始化列表没有元素,则隐式转换序列是标识转换.[...]
const std::pair<int,int>临时from 的构造{}被认为是用户定义的转换.一个建设const std::pair<int,int> *prvalue,或const int *prvalue,或const int临时对象都被认为是标准的转换.
标准转化优先于用户定义的转化.
您自己找到的CWG问题1536是相关的,但主要针对语言律师.这是措辞上的一个空白,标准并没有真正说明参考参数的初始化会发生什么{},因为{}它不是表达式.这不是什么使得这个调用模糊不清而另一个调用不是,并且实现正在设法应用这里的常识.