Consider a custom type that is meant to multiply and divide a specific instantiation of a duration:
#include <chrono>
#include <iostream>
class Foo {};
using Duration = std::chrono::seconds;
inline Duration operator*(Duration d, Foo) {
std::cout << "multiplying some time with Foo\n";
return d;
}
inline Duration operator/(Duration d, Foo) {
std::cout << "dividing some time by Foo\n";
return d;
}
int main() {
Duration d;
Foo f;
d * f;
d / f;
}
This code compiles without warnings with gcc, but fails with clang (wandbox)
In file included from prog.cc:1:
/opt/wandbox/clang-7.0.0/include/c++/v1/chrono:1259:81: error: no type named 'type' in 'std::__1::common_type<long long, Foo>'
typename common_type<typename _Duration::rep, _Rep2>::type>::value>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
/opt/wandbox/clang-7.0.0/include/c++/v1/chrono:1272:7: note: in instantiation of default argument for '__duration_divide_imp<std::__1::chrono::duration<long long, std::__1::ratio<1, 1> >, Foo>' required here
: __duration_divide_imp<duration<_Rep1, _Period>, _Rep2>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/wandbox/clang-7.0.0/include/c++/v1/chrono:1279:10: note: in instantiation of template class 'std::__1::chrono::__duration_divide_result<std::__1::chrono::duration<long long, std::__1::ratio<1, 1> >, Foo, false>' requested here
typename __duration_divide_result<duration<_Rep1, _Period>, _Rep2>::type
^
prog.cc:22:7: note: while substituting deduced template arguments into function template 'operator/' [with _Rep1 = long long, _Period = std::__1::ratio<1, 1>, _Rep2 = Foo]
d / f;
Note that operator*
works just fine with both compilers.
The actual code is a bit more convoluted, using a friend method defined within a class-scope type which performs overflow-safe integer operation on durations, but shows exactly the same symptoms.
The issue looks similar to: User-defined overloaded operator * with std::chrono::duration, but that's a different operator and compiler.
This looks like a libc++ bug to me (and a bug I wrote). Here is a very lightly tested fix:
--- a/include/chrono
+++ b/include/chrono
@@ -1289,7 +1289,12 @@ struct __duration_divide_result<duration<_Rep1, _Period>, _Rep2, false>
template <class _Rep1, class _Period, class _Rep2>
inline _LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR
-typename __duration_divide_result<duration<_Rep1, _Period>, _Rep2>::type
+typename enable_if
+<
+ !__is_duration<_Rep2>::value &&
+ is_convertible<_Rep2, typename common_type<_Rep1, _Rep2>::type>::value,
+ duration<typename common_type<_Rep1, _Rep2>::type, _Period>
+>::type
operator/(const duration<_Rep1, _Period>& __d, const _Rep2& __s)
{
typedef typename common_type<_Rep1, _Rep2>::type _Cr;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With