Подтвердить что ты не робот

Преобразование неоднозначно в Visual Studio 2015, но не с clang

Следующий код, упрощенная версия кода, найденная в проекте googlemock, не скомпилируется в Visual Studio 2015 Update 1, но компилируется на clang [Apple LLVM version 7.0.0 (clang-700.1.76)].

struct ConvertibleFromAny
{
    ConvertibleFromAny(int a_value);

    template <typename T>
    ConvertibleFromAny(const T& a_value);
};

template <typename T>
struct Matcher
{
    Matcher(T value);
};

template <typename Rhs>
struct EqMatcher
{
    explicit EqMatcher(const Rhs& rhs);

    template <typename Lhs>
    operator Matcher<Lhs>() const;
};

int main()
{
    EqMatcher<ConvertibleFromAny> em(1);
    Matcher<ConvertibleFromAny> m = em;

    return 0;
}

Ошибка выполняется в присваивании

Matcher<ConvertibleFromAny> m = em;

и сообщение об ошибке

error C2440: 'initializing': cannot convert from 'EqMatcher<ConvertibleFromAny>' to 'Matcher<ConvertibleFromAny>'
note: No constructor could take the source type, or constructor overload resolution was ambiguous

Я могу наивно видеть двусмысленность между вызовом участника на

EqMatcher<ConvertibleFromAny>::operator Matcher<ConvertibleFromAny>()

и инициализация, концептуально похожая на

Matcher<ConvertibleFromAny> m(ConvertibleFromAny<EqMatcher<ConvertibleFromAny>>(em))

Я предполагаю, что clang исключает второй вариант.

EDIT: Вдохновленный T.C. Я протестировал следующее:

struct A
{
};

struct X
{
    X(const A&);
};

struct B
{
    B(const X&);
};

int main()
{
    A a;

    B b = a;
}

Он компилируется с VS 2015, но не с clang. Я не смог найти никаких ссылок на эти документы, которые Visual С++-реализация намеренно отклоняется от стандарта в этом отношении.

Является ли это общеизвестной проблемой?

4b9b3361

Ответ 1

Оба образца кода выдают ожидаемый результат с помощью обновления VS2015 Update 1, если я включаю флаг "Disable Language Extensions" (/Za). То есть, первый компилируется, второй - нет.

Я не уверен, что расширение, в частности, вмешивается здесь. Я нашел эту страницу MSDN: Расширения Microsoft для C и С++, но она не кажется полной: например, привязка неконстантного T & на rvalue не упоминается.

Ответ 2

Я не смог найти ссылки на те документы, которые Внедрение Visual С++ намеренно отклоняется от стандарта в в этом отношении.

Здесь вы найдете: Предупреждение о компиляторе (уровень 1) C4928. Сообщение

незаконная копия-инициализация; более чем одно пользовательское преобразование было применено неявно

Он также говорит следующее:

Компилятор выполнил код во всех таких подпрограммах.

Итак, существует де-факто языковое расширение, которое Microsoft только мало документировала.

Вы можете использовать аргумент командной строки /we4928, чтобы преобразовать предупреждение в сообщение об ошибке, эффективно удалив это одно расширение. См. здесь для этих аргументов.