MSVC C++ ADL 错误?

MSVC C++ ADL bug?

此代码适用于 GCC 和 Clang。当使用自定义类型而不是 std::chrono::duration 时,它在 MSVC 中工作正常。在 operator* 上使用 operator+ 时效果很好。它适用于 MSVC pre 2018 而不是 2017/2015。

我是否遗漏了任何明显的东西,或者这只是 MSVC 中的一个错误? https://godbolt.org/z/EUWV7e

为了完整起见,这里是上面的测试用例link:

#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;
}

来自 <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::minutesduration<int, ratio<60>> -- _Rep2int。现在 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 不知何故 "intercepted"。如果你从 Foo 的 ctor 中删除 explicit——它就会消失。

我不是很熟悉 SFINAE 行为的细节,但是 cppreference.com 有一个奇怪的注释:

Only the failures in the types and expressions in the immediate context of the function type or its template parameter types or its explicit specifier (since C++20) are SFINAE errors. If the evaluation of a substituted type/expression causes a side-effect such as instantiation of some template specialization, generation of an implicitly-defined member function, etc, errors in those side-effects are treated as hard errors.

我不确定这是否适用于您的情况...如果适用 - 那么 MS 编译器是正确的,但他们的标准库有问题。如果不是——那么它可能是编译器中的一个问题。

编辑: 显然 MS problems 使用 SFINAE 一段时间...

我已将此报告给 https://developercommunity.visualstudio.com/content/problem/381899/adl-sfinae-bug-in-mvc20152017-when-using-stdchrono.html 的 MSVC 团队,他们已确认这是 MSVC 中的错误,并已在最新版本的 MSVC2017 中修复。感谢讨论!