Несколько пользовательских преобразований при инициализации

Я осознаю тот факт, что 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/ в качестве меры предосторожности.

Другие вопросы по тегам