转换在Visual Studio 2015中不明确,但与clang不同

Nie*_*sen 30 c++ clang visual-studio-2015

以下代码是googlemock项目中的代码的简化版本,无法在Visual Studio 2015 Update 1中编译,但它在clang [Apple LLVM版本7.0.0(clang-700.1.76)]上编译.

struct ConvertibleFromAny
{
    ConvertibleFromAny(int a_value);

    template <typename T>
    ConvertibleFromAny(const T& a_value);
};

template <typename T>
struct Matcher
{
    Matcher(T value);
};

template <typename Rhs>
struct EqMatcher
{
    explicit EqMatcher(const Rhs& rhs);

    template <typename Lhs>
    operator Matcher<Lhs>() const;
};

int main()
{
    EqMatcher<ConvertibleFromAny> em(1);
    Matcher<ConvertibleFromAny> m = em;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

错误发生在 分配 声明

Matcher<ConvertibleFromAny> m = em;
Run Code Online (Sandbox Code Playgroud)

并且错误消息是

error C2440: 'initializing': cannot convert from 'EqMatcher<ConvertibleFromAny>' to 'Matcher<ConvertibleFromAny>'
note: No constructor could take the source type, or constructor overload resolution was ambiguous
Run Code Online (Sandbox Code Playgroud)

我可以天真地看到成员电话之间的歧义

EqMatcher<ConvertibleFromAny>::operator Matcher<ConvertibleFromAny>()
Run Code Online (Sandbox Code Playgroud)

和概念上类似的初始化

Matcher<ConvertibleFromAny> m(ConvertibleFromAny<EqMatcher<ConvertibleFromAny>>(em))
Run Code Online (Sandbox Code Playgroud)

我的猜测是clang排除了第二种选择.

编辑:受TC的评论启发,我测试了以下内容:

struct A
{
};

struct X
{
    X(const A&);
};

struct B
{
    B(const X&);
};

int main()
{
    A a;

    B b = a;
}
Run Code Online (Sandbox Code Playgroud)

它与VS 2015编译,但不与clang编译.我无法找到任何文档,即Visual C++实现在这方面有意偏离标准.

这是一个众所周知的问题吗?

mel*_*k47 12

如果我启用"禁用语言扩展"(/Za)标志,那么您的代码示例都会使用VS2015 Update 1生成预期结果.也就是说,第一个编译,第二个编译不编译.

不过,我不确定哪个扩展特别干扰.我找到了这个MSDN页面:C和C++的Microsoft Extensions,但它似乎并不完整 - 例如,没有提到将非const T&绑定到rvalue.


eh9*_*eh9 5

我无法找到任何文档,即Visual C++实现在这方面有意偏离标准.

在这里:编译器警告(级别1)C4928.信息是

非法复制初始化; 隐式应用了多个用户定义的转换

这样说:

编译器在所有这些例程中执行了代码.

所以有一个事实上的语言扩展,微软几乎没有记录.

您可以使用命令行参数/we4928将警告转换为错误,从而有效地删除此单个扩展.请参阅此处了解这些参数.