"explicit"构造函数对过载解决的影响
Influence of "explicit" constructors in 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);
}
错误:
1>------ Build started: Project: exp_construct_test, Configuration: Debug Win32 ------
1> exp_construct_test.cpp
1>e:exp_construct_testexp_construct_test.cpp(23): error C2668: 'F' : ambiguous call to overloaded function
1> e:exp_construct_testexp_construct_test.cpp(19): could be 'void F(A<short>)'
1> e:exp_construct_testexp_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 ==========
编辑:我下载了clang并使用clang-cl编译,它报告了两种情况的错误。因此,正如评论中指出的那样,歧义介于A<short>(short)
和B(E)
之间。
所以也许VC++中有一个错误,当我从A(unsigned long)
中删除explicit
时,编译器无论意图选择B(E(还是引发歧义错误。任何人都可以确认 clang 行为符合标准,而 VC++ 有缺陷吗?
我添加了
void G(E) {};
void G(short) {};
并像这样调用 G:
G(e1_0);
这不会引发任何错误。为什么这里G(E)
是预先的,而对于A<short>::A(short)
和B::B(E)
的候选人,他们是模棱两可的?
结束编辑
谢谢--乔亚
让我们一个接一个地看一下您的示例的各种变体。
-
调用
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)
在三种可能性中
- 将
e0
转换为unsigned long
,通过构造函数 (2( 从中创建A<short>
并调用重载 (6(, - 将
e0
转换为short
,通过构造函数 (3( 从中创建A<hort>
并调用重载 (6( 和 - 通过构造函数从
e0
创建B
(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) };
这三个选项保持不变,但这一次,这三个选项都适用,调用(甚至更加(模棱两可,程序格式不正确。
-
让我们使两个构造函数都
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) };
这使得隐式构造
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) };
这一次,这三条转换路径都不适用,因为每条路径都将通过一个
explicit
构造函数。 没有适用的f
过载,程序格式不正确。 -
呼叫
g(e0)
.我们在这里有两种可能性:
- 调用过载 (8( 没有任何转换或
- 将
e0
转换为short
并调用重载 (9(。
在这两者中,第一种选择显然是有利的,因为它不涉及转换。 电话是明确的。 (即使构造函数 (5( 不是
explicit
。
请注意,默认构造函数 (1( 和 (4( 实际上对本次讨论没有任何贡献。 使用 GCC 4.9.1 进行测试,所有五个示例的行为都符合预期。
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 运行同一解决方案的另一个项目的项目
- Project Euler问题4的错误解决方案
- Ardunio UNO解决了多个重叠的定时器循环
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 两个文件使用彼此的功能-如何解决
- 计算每个节点的树高,帮助我解释这个代码解决方案
- 如何解决"invalid conversion from 'char' to 'const char*'"
- 在java中解决这段代码时面临循环中的问题
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- 难以理解某些人解决IOI问题的源代码
- visual c++,如何获取解决方案目录中的代码
- 如何解决错误:SCIP C++中的 SCIP 阶段无效 <10>
- 节俭并发:未解决的外部问题
- IpOpt拒绝解决不受约束的问题
- 如何解决这个超硬恒星的创造问题
- 循环无限运行C++解决骑士之旅问题
- 当只有静态方法受到影响时,如何解决C++中的链接器错误?
- "explicit"构造函数对过载解决的影响
- LTO优化负面影响并找到最佳解决方案