Ошибка MSVC C ++ ADL? - PullRequest
       40

Ошибка MSVC C ++ ADL?

0 голосов
/ 13 ноября 2018

Этот код прекрасно работает с GCC и Clang. Он отлично работает в MSVC при использовании пользовательского типа вместо std :: chrono :: duration. Он отлично работает при использовании operator+ над operator*. Он отлично работает с MSVC до 2018 года вместо 2017/2015.

Я что-то упускаю, или это просто ошибка в MSVC? https://godbolt.org/z/EUWV7e

Для полноты вот контрольный пример по вышеуказанной ссылке:

#include <chrono>

namespace A {
    class Foo {
    public:
        int mCount;
        constexpr explicit Foo(int count) : mCount( count ) {}
    };

    template<class Rep, class Period>
    inline Foo
    operator*(const Foo foo1, const std::chrono::duration<Rep, Period> duration) {
        return Foo(foo1.mCount * duration.count());
    }

    // For testing purposes, this is identical to operator* above.
    template<class Rep, class Period>
    inline Foo
    operator+(const Foo foo1, const std::chrono::duration<Rep, Period> duration) {
        return Foo(foo1.mCount * duration.count());
    }
}

int main() {
    A::Foo foo1(50);

    // This fails to compile for some reason?  Changing the '*' to a '+' works fine however.
    auto foo2 = foo1 * std::chrono::minutes(15);
    return foo2.mCount;
}

Ответы [ 2 ]

0 голосов
/ 16 ноября 2018

Я сообщил об этом команде MSVC по номеру https://developercommunity.visualstudio.com/content/problem/381899/adl-sfinae-bug-in-mvc20152017-when-using-stdchrono.html, и они подтвердили, что это ошибка в MSVC, и она была исправлена ​​в последней версии MSVC2017.Спасибо за обсуждения!

0 голосов
/ 14 ноября 2018

из <chrono>:

template<class _Rep1,
    class _Rep2,
    class _Period2> inline
    constexpr typename enable_if<is_convertible<_Rep1,
        typename common_type<_Rep1, _Rep2>::type>::value,
        duration<typename common_type<_Rep1, _Rep2>::type, _Period2> >::type
        operator*(
            const _Rep1& _Left,
            const duration<_Rep2, _Period2>& _Right) ...

Обратите внимание, что поскольку std::chrono::minutes равно duration<int, ratio<60>> - _Rep2 равно int.Теперь common_type<_Rep1, _Rep2> расширяется до (см. <type_traits>):

    struct common_type  // <Foo, int>
    {   // type is common type of Foo and int for two arguments
        typedef typename decay<
            decltype(false ? declval<Foo>() : declval<int>())
        >::type type;
    };

Наблюдаемая вами ошибка - это жалоба оператора, которая каким-то образом не «перехватывается» SFINAE.Если вы удалите explicit из ctor'а Фу - он уйдет.

Я не очень хорошо знаком с тонкостями поведения SFINAE, но cppreference.com имеет любопытное примечание:

Только ошибки в типах и выражениях в непосредственном контексте типа функции или ее типов параметров шаблона или ее явного спецификатора (начиная с C ++ 20) являются ошибками SFINAE.Если оценка замещенного типа / выражения вызывает побочный эффект, такой как создание некоторой специализации шаблона, генерирование неявно определенной функции-члена и т. Д., Ошибки в этих побочных эффектах рассматриваются как серьезные ошибки.

Я не уверен, что это применимо к вашему случаю ... Если это так, то компилятор MS прав, но у их std lib есть проблема.Если это не так - то это, вероятно, проблема в компиляторе.

Редактировать: очевидно, у MS было проблем с SFINAE на некоторое время ...

...