当我发现下面的代码输出“指针”时,我遇到了现实生活中的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({});
}
改变std::pair<int,int>
的模板参数int
或任何其他原始类型,给出(至少对我来说)预期的“不明确的过载”错误。似乎内置类型在这里很特殊,因为任何用户定义的类型(聚合、非平凡、带有默认构造函数等)都会导致调用指针重载。我相信模板并不是复制它所必需的,它只是让尝试不同类型变得简单。
就我个人而言,我认为这不符合逻辑,并且无论模板参数如何,我都希望在所有情况下都会出现不明确的重载错误。 GCC 和 Clang(我相信 MSVC)在 C++11/14/1z 上都不同意我的观点。注意我完全意识到这两个重载存在的坏 API,而且我永远不会写像这样的事情,我保证 https://github.com/qt/qtbase/blob/dev/src/corelib/thread/qfutureinterface.h#L179.
所以问题就变成了:到底发生了什么事?
哦,这太恶心了。
根据 [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>
暂时从{}
被视为用户定义的转换。建设一个const std::pair<int,int> *
右值,或const int *
右值,或const int
临时对象都被视为标准转换。
标准转换优于用户定义的转换。
你自己发现的CWG 问题 1536 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1536是相关的,但主要针对语言律师。这是措辞上的一个空白,标准并没有真正说明参考参数的初始化会发生什么{}
, since {}
不是一个表达式。这并不是导致一个调用不明确而另一个调用不明确的原因,并且实现在这里设法应用常识。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)