转换运算符重载歧义,编译器不同

Rol*_*lle 8 c++ gcc operators visual-studio

我已经看到了关于此的其他问题,但没有一个完全解释它.编译器处理以下两种情况的正确方法是什么?我用gcc 4.7.1(使用-std = c ++ 0x),VS2010和VS2012尝试了一下,得到了不同的结果:

例1:

struct BB
{
 // generic cast
 template<typename T>
 operator T() const
 {   
   return 0;
 }

 // string cast
 operator std::string() const
 { 
   return string("hello");
 }
};

int main()
{
  BB b;
  string s = b;
}
Run Code Online (Sandbox Code Playgroud)

输出:

  • gcc 4.7.1:好的
  • VS2010:好的
  • VS2012:失败:"无法从BB转换为字符串"

例2:

struct BB
{
 // generic cast
 template<typename T>
 operator T() const
 {   
   return 0;
 }

 // string cast
 operator std::string() const
 { 
   return string("hello");
 }
};

int main()
{
  BB b;
  string s = (string)b;
Run Code Online (Sandbox Code Playgroud)

输出:

  • gcc 4.7.1:失败:调用重载字符串(BB&)是不明智的
  • VS2010:好的
  • VS2012:失败:"无法从BB转换为字符串"

Dav*_*men 5

你的第二个带有 C 风格演员阵容的版本是不明确的。问题是有两种方法static_cast<std::string>可以将类的实例转换BB为字符串。明显的路径是使用非模板 std::string 强制转换运算符直接转换为字符串。还有一条更迂回的道路,除了 VS2010 之外,其他人都发现了它。另一条路径是使用模板强制转换运算符将 a 转换BB为字符串的分配器,然后使用此分配器构造一个空字符串。

模板转换运算符是潜在的危险野兽。BB您刚刚为编译器提供了将 a 转换为任何内容的工具。

您的第一个版本避免了这个问题,因为它std::basic_string(const _Alloc& __a)是一个显式构造函数。显式构造函数可以用于显式转换,但不能用于隐式转换。正是这个构造函数加上到分配器的转换造成了歧义,并且该路径不能与隐式转换一起使用。

至于为什么 VS1012 在隐式转换上失败,这可能是 VS2012 中的一个错误,也可能是 C++11 创建了更多从 a 到BBa 的途径std::string。我不是 C++11 专家。我什至不是新手。

还有一项:如果您使用的话,您的代码将会失败得更惨

 std::string s;
 s = b;
Run Code Online (Sandbox Code Playgroud)

赋值运算符与模板转换运算符结合使用,创建了更多从 到 的b方法s。系统应该转换b为 a std::string、 achar还是 a char*

底线:您确实应该重新考虑模板转换运算符的使用。