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::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 不知何故 "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 中修复。感谢讨论!
此代码适用于 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::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 不知何故 "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 中修复。感谢讨论!