使用空大括号初始值设定项的重载解析:指针还是引用?
Overload resolution with an empty brace initializer: pointer or reference?
当我发现下面的代码输出 "pointer".
时,我 运行 陷入了现实生活中的 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
或任何其他原始类型,会出现(至少对我而言)预期的 "ambiguous overload" 错误。似乎内置类型在这里很特殊,因为任何用户定义的类型(聚合、非平凡、具有默认构造函数等)都会导致调用指针重载。我相信模板不是复制它所必需的,它只是让尝试不同类型变得简单。
就我个人而言,我认为这不合逻辑,我希望在所有情况下都会出现模棱两可的重载错误,无论模板参数如何。 GCC 和 Clang(我相信 MSVC)在 C++11/14/1z 上都不同意我的观点。请注意,我完全清楚 API 这两个重载存在的问题,我永远不会写 something like this, I promise.
所以问题就变成了:这是怎么回事?
哦,这太恶心了。
根据 [over.ics.list]p4 和 p7:
4 Otherwise, if the parameter is a non-aggregate class X
and overload resolution per 13.3.1.7 chooses a single best constructor of X
to perform the initialization of an object of type X
from the argument initializer list, the implicit conversion sequence is a user-defined conversion sequence with the second standard conversion sequence an identity conversion. [...]
[...]
6 Otherwise, if the parameter is a reference, see 13.3.3.1.4. [Note: The rules in this section will apply for initializing the underlying temporary for the reference. -- end note] [...]
[...]
7 Otherwise, if the parameter type is not a class:
[...]
(7.2) -- if the initializer list has no elements, the implicit conversion sequence is the identity conversion. [...]
从 {}
构建 const std::pair<int,int>
临时文件被认为是用户定义的转换。 const std::pair<int,int> *
纯右值、const int *
纯右值或 const int
临时对象的构造都被视为标准转换。
标准转换优先于用户定义的转换。
您自己发现的 CWG issue 1536 是相关的,但主要针对语言律师。这是措辞上的一个空白,标准并没有真正说明从 {}
初始化参考参数会发生什么,因为 {}
不是表达式。这并不是使一个调用模棱两可而另一个调用模棱两可的原因,并且实现正在设法在这里应用常识。
当我发现下面的代码输出 "pointer".
时,我 运行 陷入了现实生活中的 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
或任何其他原始类型,会出现(至少对我而言)预期的 "ambiguous overload" 错误。似乎内置类型在这里很特殊,因为任何用户定义的类型(聚合、非平凡、具有默认构造函数等)都会导致调用指针重载。我相信模板不是复制它所必需的,它只是让尝试不同类型变得简单。
就我个人而言,我认为这不合逻辑,我希望在所有情况下都会出现模棱两可的重载错误,无论模板参数如何。 GCC 和 Clang(我相信 MSVC)在 C++11/14/1z 上都不同意我的观点。请注意,我完全清楚 API 这两个重载存在的问题,我永远不会写 something like this, I promise.
所以问题就变成了:这是怎么回事?
哦,这太恶心了。
根据 [over.ics.list]p4 和 p7:
4 Otherwise, if the parameter is a non-aggregate class
X
and overload resolution per 13.3.1.7 chooses a single best constructor ofX
to perform the initialization of an object of typeX
from the argument initializer list, the implicit conversion sequence is a user-defined conversion sequence with the second standard conversion sequence an identity conversion. [...][...]
6 Otherwise, if the parameter is a reference, see 13.3.3.1.4. [Note: The rules in this section will apply for initializing the underlying temporary for the reference. -- end note] [...]
[...]
7 Otherwise, if the parameter type is not a class:
[...]
(7.2) -- if the initializer list has no elements, the implicit conversion sequence is the identity conversion. [...]
从 {}
构建 const std::pair<int,int>
临时文件被认为是用户定义的转换。 const std::pair<int,int> *
纯右值、const int *
纯右值或 const int
临时对象的构造都被视为标准转换。
标准转换优先于用户定义的转换。
您自己发现的 CWG issue 1536 是相关的,但主要针对语言律师。这是措辞上的一个空白,标准并没有真正说明从 {}
初始化参考参数会发生什么,因为 {}
不是表达式。这并不是使一个调用模棱两可而另一个调用模棱两可的原因,并且实现正在设法在这里应用常识。