C++ 涉及模板转换运算符和隐式复制构造函数的歧义

C++ 涉及模板转换运算符和隐式复制构造函数的歧义,c++,templates,c++11,overload-resolution,conversion-operator,C++,Templates,C++11,Overload Resolution,Conversion Operator,对于以下代码,clang和gcc的行为有所不同: struct foo { foo(int); }; struct waldo { template <typename T> operator T(); }; int main() { waldo w; foo f{w}; } 谁是对的 还值得注意的是,如果foo f{w}更改为foo f(w)(注意从大括号到括号的更改),那么gcc和clang都会给出一个错误。这使我希望gcc在上述示例

对于以下代码,clang和gcc的行为有所不同:

struct foo
{
    foo(int);
};

struct waldo
{
    template <typename T>
    operator T();
};

int main()
{
    waldo w;
    foo f{w};
}
谁是对的

还值得注意的是,如果
foo f{w}
更改为
foo f(w)
(注意从大括号到括号的更改),那么gcc和clang都会给出一个错误。这使我希望gcc在上述示例中的行为(即给出错误)是正确的,否则,
()
{}
初始化形式之间会出现奇怪的不一致

编辑:根据Kerrek SB的建议,我尝试了
删除
foo的复制构造函数

struct foo
{
    foo(int);
    foo(const foo&) = delete;
};

行为保持不变。

对于列表初始化,如果列表的元素有一个元素(此处为
w
),并且考虑带有参数“reference to const/volatile X”的类
X
的构造函数,则不考虑用户定义的转换。因此,
foo
的复制和移动构造函数都不能使用。因此,
foo(int)
构造函数是明确选择的

所以这里的叮当声是正确的


编辑:对于这里的标准人员,请参见13.3.3.1p4,我将在这一点上使用GCC:到
int
和到
Foo
的转换都是可能的,因此这看起来很模糊。不过,请尝试删除或默认复制/移动构造函数,并进行比较。@KerrekSB删除的函数确实参与重载解析。@rhalbersma:这一点很好!显然(根据的幻灯片17),这种类型的括号初始化不能用于C++11中的复制,这将使Clang正确。它被视为一个缺陷,可能在C++14中修复,使GCC正确。然而,我似乎在C++11中找不到阻止它的措辞,所以我不能给出一个明确的答案。@MikeSeymour:litb,当然了:p谢谢比亚恩的演讲,顺便说一句,我还没有看到它!
struct foo
{
    foo(int);
    foo(const foo&) = delete;
};