MSVC C ++ ADL错误?

时间:2018-11-13 20:57:52

标签: c++ visual-c++ argument-dependent-lookup

此代码可与GCC和Clang一起正常使用。当使用自定义类型而不是std :: chrono :: duration时,它在MSVC中工作正常。在operator+上使用operator*时,效果很好。它可以在2018年之前的MSVC(而不是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 :(得分:1)

来自<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并未以某种方式“拦截”。如果您从Foo的ctor中删除explicit,它将消失。

我对SFINAE行为的细节并不十分熟悉,但是cppreference.com有一个有趣的提示:

  

仅立即类型和表达式中的失败   函数类型或其模板参数类型或其上下文的上下文   显式说明符(自C ++ 20起)是SFINAE错误。如果评价   类型/表达式的替换会引起诸如   模板专业化的实例化,生成一个   隐式定义的成员函数等,这些副作用中的错误   被视为硬错误。

我不确定这是否适用于您的情况...如果确实如此-则MS编译器是正确的,但是其std lib有问题。如果不是,则可能是编译器中的一个问题。

编辑:显然,MS与SFINAE已有problems了...

答案 1 :(得分:0)

我已通过https://developercommunity.visualstudio.com/content/problem/381899/adl-sfinae-bug-in-mvc20152017-when-using-stdchrono.html向MSVC小组报告了此问题,他们已经确认这是MSVC中的错误,并且已在最新版本的MSVC2017中修复。感谢您的讨论!