在Visual Studio 2015中,转换是不明确的,但与clang无关。

时间:2021-11-27 02:33:08

The following code, a simplified version of code found in the googlemock project, fails to compile in Visual Studio 2015 Update 1, but it compiles on clang [Apple LLVM version 7.0.0 (clang-700.1.76)].

以下代码是在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;
}

The error occurs at the assignment statement

错误发生在赋值语句中

Matcher<ConvertibleFromAny> m = em;

and the error message is

错误信息是

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

I can naively see an ambiguity between a member call to

我可以天真地看到成员调用之间的模糊性

EqMatcher<ConvertibleFromAny>::operator Matcher<ConvertibleFromAny>()

and an initialization conceptually similar to

初始化的概念与

Matcher<ConvertibleFromAny> m(ConvertibleFromAny<EqMatcher<ConvertibleFromAny>>(em))

My guess is that clang rules out the second option.

我猜clang排除了第二种选择。

EDIT: Inspired by T.C.'s comment I tested the following:

编辑:灵感来自于教学楼。我测试了以下内容:

struct A
{
};

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

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

int main()
{
    A a;

    B b = a;
}

It compiles with VS 2015, but not with clang. I have not been able to find any references that documents that the Visual C++ implementation intentionally deviates from the standard in this regard.

它编译VS 2015,但不编译clang。我没有找到任何参考文献,证明Visual c++实现在这方面故意偏离了标准。

Is this a well-known problem?

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

2 个解决方案

#1


12  

Both your code samples produce the expected result with VS2015 Update 1, if I enable the "Disable Language Extensions" (/Za) flag. That is, the first one compiles, the second one does not.

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

I'm not sure which extension in particular is interfering here, though. I found this MSDN page: Microsoft Extensions to C and C++, but it does not appear to be complete - for example, binding a non-const T& to an rvalue is not mentioned.

不过,我不确定具体是哪个扩展影响了这里。我找到了这个MSDN页面:对C和c++的Microsoft扩展,但它似乎并不完整——例如,没有提到将非const t&a绑定到rvalue。

#2


5  

I have not been able to find any references that documents that the Visual C++ implementation intentionally deviates from the standard in this regard.

我没有找到任何参考文献,证明Visual c++实现在这方面故意偏离了标准。

Here you go: Compiler Warning (level 1) C4928. The message is

这里是:编译器警告(第一级)C4928。消息是

illegal copy-initialization; more than one user-defined conversion has been implicitly applied

非法copy-initialization;已经隐式地应用了多个用户定义的转换

It also says this:

它还说:

The compiler executed the code in all such routines.

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

So there's a de facto language extension that Microsoft has only barely documented.

所以事实上有一种语言扩展,微软几乎没有记录。

You can use command line argument /we4928 to convert the warning into an error, effectively removing this single extension. See here for these arguments.

您可以使用命令行参数/we4928将警告转换为错误,有效地删除此单个扩展。看看这些论点。

#1


12  

Both your code samples produce the expected result with VS2015 Update 1, if I enable the "Disable Language Extensions" (/Za) flag. That is, the first one compiles, the second one does not.

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

I'm not sure which extension in particular is interfering here, though. I found this MSDN page: Microsoft Extensions to C and C++, but it does not appear to be complete - for example, binding a non-const T& to an rvalue is not mentioned.

不过,我不确定具体是哪个扩展影响了这里。我找到了这个MSDN页面:对C和c++的Microsoft扩展,但它似乎并不完整——例如,没有提到将非const t&a绑定到rvalue。

#2


5  

I have not been able to find any references that documents that the Visual C++ implementation intentionally deviates from the standard in this regard.

我没有找到任何参考文献,证明Visual c++实现在这方面故意偏离了标准。

Here you go: Compiler Warning (level 1) C4928. The message is

这里是:编译器警告(第一级)C4928。消息是

illegal copy-initialization; more than one user-defined conversion has been implicitly applied

非法copy-initialization;已经隐式地应用了多个用户定义的转换

It also says this:

它还说:

The compiler executed the code in all such routines.

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

So there's a de facto language extension that Microsoft has only barely documented.

所以事实上有一种语言扩展,微软几乎没有记录。

You can use command line argument /we4928 to convert the warning into an error, effectively removing this single extension. See here for these arguments.

您可以使用命令行参数/we4928将警告转换为错误,有效地删除此单个扩展。看看这些论点。