12

为什么 Visual Studio 2010 和 Visual Studio 2012 无法编译此代码?

Codepad.org、Xcode、gcc、LLVM、Clang 都没有问题,但 Visual Studio 会大便:

struct S {
  template <class T> inline operator T () const { return T (); }
};
int main () {
  // NOTE: "S()" denotes construction in these examples
  struct F {
    void operator() (bool) { }
    static void toint (int) { }
    static void tostr (char const*) { }
  };
  bool b1 = S (); // Okay
  bool b2 (S ()); // Okay
  F () (S ());    // Okay
  F::toint (S ());// Okay
  F::tostr (S ());// Okay

  S () || false;  // Error: error C2676: binary '||' : 'vf::S' does
                  // not define this operator or a conversion to a type
                  // acceptable to the predefined operator
  return 0;
}

添加explicit关键字不会改变 gcc 或 clang 的任何事情。产生的错误信息是:

error C2676: binary '||' : 'S' does not define this operator or a
  conversion to a type acceptable to the predefined operator
4

2 回答 2

3

这是一个错误,至少在 C++03 中(不确定 C++11)。

根据 C++03 §13.3.1.2 中的重载决策规则,选择内置||运算符,因为没有||S.

§5.15/1 说:

||运算符从左到右分组。操作数都被隐式转换为bool(第 4 条)。[...]

§12.3/2 说:

用户定义的转换仅适用于明确的情况(10.2、12.3.2)。[...]

§12.3/5:

仅当用户定义的转换明确时,才会隐式使用它们。[...] 函数重载决议 (13.3.3) 选择最佳转换函数来执行转换。

§13.3.2/3:

其次,为了F成为一个可行的函数,每个参数都应该存在一个隐式转换序列(13.3.3.1),该序列将该参数转换为对应的参数F

明确S定义了用户定义的转换为bool. 内置||运算符是重载决议的可行函数,因为它是唯一的,所以它是最好的。所以表达式是良构的。

另外值得注意的是§4/3,它说:

当且仅当声明“<code>T t=e;”时,表达式e可以隐式转换为类型 T对于一些发明的临时变量t(8.5),是良构的。[...]

所以我很好奇 Visual Studio 是否也会为语句产生错误bool b = S();

于 2012-11-24T17:48:06.227 回答
0

如果您禁止将隐式类型转换为布尔值,编译器必须检查是否存在运算符|| 定义 wich 需要一个布尔值。这是(希望!)未定义,因为它会破坏快捷方式。所以他必须检查是否定义了一个转换操作符,它为全局 || 操作符定义了一些东西。你能通过在 bool、BOOL 或 int 中添加一个转换运算符来解决这个问题吗(无论如何都是一样的^^)......?

operator bool() {return this != null && this != 0xcccccccc;}

这个 BTW 只是一个 hack,最好提供一个逻辑上有意义的转换。

我在调试模式下为 0xcccccccc 标记未初始化的内存定义了一个常量,但我不知道。

于 2012-11-24T16:43:35.790 回答