joj*_*oja 5 c++ constructor visual-c++ overload-resolution
为什么以下代码不能编译,当我在A类中的构造函数之前删除显式关键字时,它编译?
使用Visual Studio 2013:
enum E { e1_0, e1_1 };
template<typename T>
struct A
{
A() {}
explicit A(unsigned long) {}
A(T) {}
};
struct B
{
B() {}
B(E) {}
};
void F(B) {};
void F(A<short>) {};
void test()
{
F(e1_0);
}
Run Code Online (Sandbox Code Playgroud)
错误:
1>------ Build started: Project: exp_construct_test, Configuration: Debug Win32 ------
1> exp_construct_test.cpp
1>e:\exp_construct_test\exp_construct_test.cpp(23): error C2668: 'F' : ambiguous call to overloaded function
1> e:\exp_construct_test\exp_construct_test.cpp(19): could be 'void F(A<short>)'
1> e:\exp_construct_test\exp_construct_test.cpp(18): or 'void F(B)'
1> while trying to match the argument list '(E)'
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Run Code Online (Sandbox Code Playgroud)
编辑:我下载了clang并使用clang-cl编译,报告了两种情况的错误.正如评论中所指出的那样,暧昧关系在A<short>(short)和之间B(E).
所以VC++中可能存在一个错误,当我explicit从中删除时A(unsigned long),编译器会以任何意图选择B(E)而不是引发一个模糊错误.任何人都可以确认clang行为符合标准,VC++是否有错误?
我补充道
void G(E) {};
void G(short) {};
Run Code Online (Sandbox Code Playgroud)
并像这样打电话给G:
G(e1_0);
Run Code Online (Sandbox Code Playgroud)
这不会引起任何错误.为什么这里G(E)被prefferred,并在候选人的情况下,A<short>::A(short)和B::B(E),他们是暧昧?
结束编辑
谢谢--joja
让我们逐个看看示例的各种变体。
原始示例调用f(e0).
enum E {e0, e1};
template<typename T>
struct A
{
A(); // (1)
explicit A(unsigned long); // (2)
A(T); // (3)
};
struct B
{
B(); // (4)
B(E); // (5)
};
void f(A<short>); // (6)
void f(B); // (7)
void g(E); // (8)
void g(short); // (9)
Run Code Online (Sandbox Code Playgroud)
在这三种可能性中
e0为 an unsigned long,A<short>通过构造函数 (2) 创建 an 并调用重载 (6),e0为,通过构造函数 (3) 从它short创建一个并调用重载 (6) 和A<hort>Bfrom e0via 构造函数 (5) 并调用重载 (7)第一个选项不适用,因为 (2) 是explicit。其余两个都涉及用户定义的转换,这两个转换被认为同样好,并且没有一个会偏向另一个。调用不明确且程序格式错误。
explicit让我们从构造函数中删除并调用f(e0)。
template<typename T>
struct A
{
A(); // (1)
A(unsigned long); // (2)
A(T); // (3)
};
struct B
{
B(); // (4)
B(E); // (5)
};
Run Code Online (Sandbox Code Playgroud)
三个选项保持不变,但这一次,所有三个选项都适用,并且调用(甚至更)不明确,并且程序格式不正确。
让我们创建构造函数explicit并调用f(e0)。
template<typename T>
struct A
{
A(); // (1)
explicit A(unsigned long); // (2)
explicit A(T); // (3)
};
struct B
{
B(); // (4)
B(E); // (5)
};
Run Code Online (Sandbox Code Playgroud)
这使得隐式构造 an 变得不可能A<short>,并且调用明确地引用重载 (5)。
让我们也B创建 的构造函数explicit并调用f(e0)。
template<typename T>
struct A
{
A(); // (1)
explicit A(unsigned long); // (2)
explicit A(T); // (3)
};
struct B
{
B(); // (4)
explicit B(E); // (5)
};
Run Code Online (Sandbox Code Playgroud)
这次,三个转换路径都不explicit适用,因为每个转换路径都会经过构造函数。没有f适用的过载,并且该程序格式不正确。
称呼g(e0)。
我们这里有两种可能性:
e0为 ashort并调用重载 (9)。在这两个选项中,第一个选项显然是有利的,因为它不涉及转换。这个呼吁是明确的。(即使构造函数 (5) 不是explicit。)
请注意,默认构造函数 (1) 和 (4) 实际上对本讨论没有任何贡献。使用 GCC 4.9.1 进行测试,所有五个示例的行为均符合预期。
| 归档时间: |
|
| 查看次数: |
204 次 |
| 最近记录: |