Несколько пользовательских преобразований при инициализации
Я осознаю тот факт, что C++ допускает только одно пользовательское неявное преобразование при преобразовании между типами. Однако недавно я столкнулся с ситуацией, когда кажется, что при инициализации допускаются двойные пользовательские неявные преобразования.
Рассмотрим следующие классы:
//fractions
class Rational {
public:
int num, den;
// default constructor, etc.
Rational(int n) : num(n), den(1) {} // NOT explicit
// arithmetic and compound assignment defined between two Rational's.
};
//numbers of the form a + b sqrt(N), where a, b are of type R
template<typename R, int N>
class RingExtension {
public:
R a, b;
// default constructor, etc.
RingExtension<R, N>(R a) : a(a), b(0) {} // NOT explicit
// arithmetic and compound assignment defined between two RingExtension<R, N>'s.
};
Как и ожидалось, следующее не скомпилируется:
int main() {
RingExtension<Rational, 2> x;
x /= 3; // ERROR! Can't do the conversion int -> Rational -> RingExtension<Rational, 2>
x /= (Rational)3; // this does work
}
Однако в Visual Studio 2013 компилируется следующее:
int main() {
RingExtension<Rational, 2> x = 3; // int -> Rational -> RingExtension<Rational, 2>
}
Почему в последней ситуации допускается двойное пользовательское преобразование? Visual Studio не соответствует стандартам в этой конкретной ситуации? Или есть какое-то исключение в стандарте для инициализации?
РЕДАКТИРОВАТЬ: Как предложил Kerrek SB, я проверил мой код в Clang и GCC через Wandbox. Оба компилятора выдавали ошибку при инициализации, как и следовало ожидать. Остается вопрос, кто здесь не прав? Казалось бы, Visual Studio слишком строгий, но было бы здорово, если бы кто-то мог это подтвердить.
РЕДАКТИРОВАТЬ: Полный исходный код для этих классов, включая функцию main(), можно найти здесь: http://pastebin.com/JNSvkwi0
1 ответ
Похоже, это нестандартное расширение Microsoft, которое можно отключить, передавили/std:c++20
(что позволяет/permissive-
по умолчанию). Я не смог найти более узкого/Zc:
вариант. Мне также не удалось найти документацию Microsoft по этому поводу.
Однако соответствующее предупреждение JetBrains ReSharper есть еще в их версии 2017.2:
Во время инициализации копирования применено более одного неявного преобразования. Это нестандартное расширение Microsoft C++.
К сожалению, ссылка на Connect.microsoft.com в комментариях больше не работает, и мне не удалось найти соответствующую тему на Visualstudio.com. Поэтому я добавил все остальные ссылки из этого ответа на https://web.archive.org/ в качестве меры предосторожности.