【发布时间】:2011-10-24 04:01:15
【问题描述】:
我今天遇到了一个相当奇怪的重载解决方案。我将其简化为以下内容:
struct S
{
S(int, int = 0);
};
class C
{
public:
template <typename... Args>
C(S, Args... args);
C(const C&) = delete;
};
int main()
{
C c({1, 2});
}
我完全期望C c({1, 2}) 匹配C 的第一个构造函数,可变参数的数量为零,并且{1, 2} 被视为S 对象的初始化列表构造。
但是,我收到一个编译器错误,表明它与已删除的 C 复制构造函数匹配!
test.cpp: In function 'int main()':
test.cpp:17:15: error: use of deleted function 'C(const C &)'
test.cpp:12:5: error: declared here
我可以看到它是如何工作的 - {1, 2} 可以解释为 C 的有效初始化程序,1 是 S 的初始化程序(它可以从 int 隐式构造,因为第二个其构造函数的参数有一个默认值),而 2 是一个可变参数......但我不明白为什么这会是一个更好的匹配,特别是看到有问题的复制构造函数被删除了。
有人可以解释一下这里起作用的重载解决规则,并说明是否存在不涉及在构造函数调用中提及 S 名称的解决方法?
编辑:由于有人提到 sn-p 使用不同的编译器进行编译,我应该澄清一下,我在 GCC 4.6.1 中遇到了上述错误。
编辑 2:我进一步简化了 sn-p 以获得更令人不安的故障:
struct S
{
S(int, int = 0);
};
struct C
{
C(S);
};
int main()
{
C c({1});
}
错误:
test.cpp: In function 'int main()':
test.cpp:13:12: error: call of overloaded 'C(<brace-enclosed initializer list>)' is ambiguous
test.cpp:13:12: note: candidates are:
test.cpp:8:5: note: C::C(S)
test.cpp:6:8: note: constexpr C::C(const C&)
test.cpp:6:8: note: constexpr C::C(C&&)
这一次,GCC 4.5.1 也给出了同样的错误(减去constexprs 和它不会隐式生成的移动构造函数)。
我发现非常很难相信这是语言设计者的意图......
【问题讨论】:
-
编译器不考虑“我可以这样称呼吗?”直到它决定“我应该叫什么”之后。因此,不幸的是,被删除的复制构造函数根本与主题无关..
-
@Dennis:SFINAE 不是反例吗?
-
@bdonlan:这样想:如果我写了
C c(C{1, 2}),它将别无选择,只能调用复制构造函数。如果我写了C c(S{1, 2}),它将别无选择,只能调用第一个构造函数。但是我写了C c({1, 2}),那么它会调用哪个呢?在常识层面上,它不应该尝试调用已删除的函数是理所当然的......但是编译器在常识上从来都不是强大的,是吗? =P -
我觉得有某种括号/括号可以解决这个问题。
-
@HighCommander4:调用和模板实例化是不同的——在这种情况下,甚至没有尝试模板实例化
标签: c++ c++11 overload-resolution