Visual Studio не создает экземпляр шаблона оператора преобразования (преобразования) (T = bool) в контексте логических операций
Почему 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
Ответы
Ответ 1
Это ошибка, по крайней мере, в С++ 03 (не уверен о С++ 11).
В соответствии с правилами разрешения перегрузки в С++ 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, в котором говорится:
Выражение e
может быть неявно преобразовано в тип T
тогда и только тогда, когда декларация "T t=e;
" корректна для некоторой изобретенной временной переменной T
(8.5). [...]
Итак, мне любопытно, создает ли Visual Studio ошибку для оператора bool b = S();
.
Ответ 2
Если вы форбируете неявное приведение типов в boolean, компилятор должен проверить, существует ли оператор || определенный, который принимает логическое значение. Это (надеюсь,!) Не определено, потому что это нарушит ярлыки. Поэтому он должен проверить, есть ли определенный оператор преобразования, который дает ему что-то определенное для глобального || -оператора. Не могли бы вы решить эту проблему, добавив оператор преобразования в bool, BOOL или int (все равно это все равно ^^)...?
operator bool() {return this != null && this != 0xcccccccc;}
Это BTW было бы просто взломом, было бы лучше обеспечить логически значимое преобразование.
Im shure существует константа, определенная для отметки 0xcccccccc для неинициализированной памяти в режиме отладки, но я ее не знаю.