以下代码是googlemock项目中的代码的简化版本,无法在Visual Studio 2015 Update 1中编译,但它在clang [Apple LLVM版本7.0.0(clang-700.1.76)]上编译.
struct ConvertibleFromAny { ConvertibleFromAny(int a_value); templateConvertibleFromAny(const T& a_value); }; template struct Matcher { Matcher(T value); }; template struct EqMatcher { explicit EqMatcher(const Rhs& rhs); template operator Matcher () const; }; int main() { EqMatcher em(1); Matcher m = em; return 0; }
错误发生在 分配 声明
Matcherm = em;
并且错误消息是
error C2440: 'initializing': cannot convert from 'EqMatcher' to 'Matcher ' note: No constructor could take the source type, or constructor overload resolution was ambiguous
我可以天真地看到成员电话之间的歧义
EqMatcher::operator Matcher ()
和概念上类似的初始化
Matcherm(ConvertibleFromAny >(em))
我的猜测是clang排除了第二种选择.
编辑:受TC的评论启发,我测试了以下内容:
struct A { }; struct X { X(const A&); }; struct B { B(const X&); }; int main() { A a; B b = a; }
它与VS 2015编译,但不与clang编译.我无法找到任何文档,即Visual C++实现在这方面有意偏离标准.
这是一个众所周知的问题吗?
如果我启用"禁用语言扩展"(/Za
)标志,那么您的代码示例都会使用VS2015 Update 1生成预期结果.也就是说,第一个编译,第二个编译不编译.
不过,我不确定哪个扩展特别干扰.我找到了这个MSDN页面:C和C++的Microsoft Extensions,但它似乎并不完整 - 例如,没有提到将非const T&绑定到rvalue.
我无法找到任何文档,即Visual C++实现在这方面有意偏离标准.
在这里:编译器警告(级别1)C4928.信息是
非法复制初始化; 隐式应用了多个用户定义的转换
它也这样说:
编译器在所有这些例程中执行了代码.
所以有一个事实上的语言扩展,微软几乎没有记录.
您可以使用命令行参数/we4928
将警告转换为错误,从而有效地删除此单个扩展.请参阅此处了解这些参数.