SFINAE 与特征检测部门有关的问题
SFINAE issue with traits detecting division
我有以下特征来检测两种类型是否可整除,并且 return 生成的操作类型或另一个 Default
类型否则:
struct default_t { };
// Overloaded template for fallbacks
template <class U, class V>
default_t operator/(U, V);
// If the expression std::declval<U>()/std::declval<V>() is valid,
// gives the return type, otherwize provide Default.
template <class U, class V, class Default>
struct div_type_or {
using type_ = decltype(std::declval<U>() / std::declval<V>());
using type = typename std::conditional<
std::is_same<type_, default_t>{},
Default,
type_>::type;
};
template <class... Args>
using div_type_or_t = typename div_type_or<Args...>::type;
这适用于 libstdc++,但不适用于 libc++,当我尝试使用不可分割的 std::chrono::duration
类型时,例如:
struct A { };
div_type_or_t<std::chrono::seconds, A, int> b;
我收到以下错误:
/Library/Developer/CommandLineTools/usr/include/c++/v1/chrono:764:81:
error: no type named 'type' in
'std::__1::common_type'
typename common_type::type>::value>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
/Library/Developer/CommandLineTools/usr/include/c++/v1/chrono:777:7:
note: in instantiation of default argument for
'__duration_divide_imp >, A>' required here
: __duration_divide_imp, _Rep2>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >
/Library/Developer/CommandLineTools/usr/include/c++/v1/chrono:784:10:
note: in instantiation of template class
'std::__1::chrono::__duration_divide_result >, A, false>'
requested here typename __duration_divide_result, _Rep2>::type
^
test.cpp:16:46: note: while substituting deduced template arguments into function template 'operator/' [with _Rep1 = long
long, _Period = std::__1::ratio<1, 1>, Rep2 = A]
using type = decltype(std::declval() / std::declval());
^
test.cpp:24:1: note: in instantiation of template class
'div_type_or >, A, D>' requested here using div_type_or_t = typename div_type_or::type; ^
test.cpp:48:19:
note: in instantiation of template type alias 'div_type_or_t'
requested here
div_type_or_t, D>{}, "");
据我了解,这是因为 std::chrono::duration
的 operator/
的以下重载失败了:
template< class Rep1, class Period, class Rep2 >
duration<typename std::common_type<Rep1,Rep2>::type, Period>
constexpr operator/( const duration<Rep1, Period>& d,
const Rep2& s );
我认为由于 std::common_type
是函数签名的一部分,这将允许 SFINAE 工作并使用我自定义的 operator/
重载,从而推导出 default_t
,但显然这不起作用...
因为这适用于 libstdc++,我只想知道我的代码是否有问题(也许我不明白 SFINAE 在这种情况下的工作方式)或者这是一个 libc++ 错误?
在 libc++ 中,我们有:
template <class _Duration, class _Rep, bool = __is_duration<_Rep>::value>
struct __duration_divide_result
{
};
template <class _Duration, class _Rep2,
bool = is_convertible<_Rep2,
typename common_type<typename _Duration::rep, _Rep2>::type>::value>
struct __duration_divide_imp
{
};
template <class _Rep1, class _Period, class _Rep2>
struct __duration_divide_imp<duration<_Rep1, _Period>, _Rep2, true>
{
typedef duration<typename common_type<_Rep1, _Rep2>::type, _Period> type;
};
template <class _Rep1, class _Period, class _Rep2>
struct __duration_divide_result<duration<_Rep1, _Period>, _Rep2, false>
: __duration_divide_imp<duration<_Rep1, _Period>, _Rep2>
{
};
template <class _Rep1, class _Period, class _Rep2>
inline _LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR
typename __duration_divide_result<duration<_Rep1, _Period>, _Rep2>::type
operator/(const duration<_Rep1, _Period>& __d, const _Rep2& __s)
{
typedef typename common_type<_Rep1, _Rep2>::type _Cr;
typedef duration<_Cr, _Period> _Cd;
return _Cd(_Cd(__d).count() / static_cast<_Cr>(__s));
}
所以 std::common_type<_Rep1, _Rep2>::type
,
他们使用 __duration_divide_result<duration<_Rep1, _Period>, _Rep2 /*, false*/>
,
实例化 __duration_divide_imp<duration<_Rep1, _Period>, _Rep2
/*, is_convertible<_Rep2, typename common_type<_Rep1, _Rep2>::type>::value*/>
该用法是一个硬错误。
我会说 libc++ 中的实现在这方面是不正确的。
我有以下特征来检测两种类型是否可整除,并且 return 生成的操作类型或另一个 Default
类型否则:
struct default_t { };
// Overloaded template for fallbacks
template <class U, class V>
default_t operator/(U, V);
// If the expression std::declval<U>()/std::declval<V>() is valid,
// gives the return type, otherwize provide Default.
template <class U, class V, class Default>
struct div_type_or {
using type_ = decltype(std::declval<U>() / std::declval<V>());
using type = typename std::conditional<
std::is_same<type_, default_t>{},
Default,
type_>::type;
};
template <class... Args>
using div_type_or_t = typename div_type_or<Args...>::type;
这适用于 libstdc++,但不适用于 libc++,当我尝试使用不可分割的 std::chrono::duration
类型时,例如:
struct A { };
div_type_or_t<std::chrono::seconds, A, int> b;
我收到以下错误:
/Library/Developer/CommandLineTools/usr/include/c++/v1/chrono:764:81: error: no type named 'type' in 'std::__1::common_type' typename common_type::type>::value> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
/Library/Developer/CommandLineTools/usr/include/c++/v1/chrono:777:7: note: in instantiation of default argument for '__duration_divide_imp >, A>' required here : __duration_divide_imp, _Rep2> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >
/Library/Developer/CommandLineTools/usr/include/c++/v1/chrono:784:10: note: in instantiation of template class 'std::__1::chrono::__duration_divide_result >, A, false>' requested here typename __duration_divide_result, _Rep2>::type ^
test.cpp:16:46: note: while substituting deduced template arguments into function template 'operator/' [with _Rep1 = long long, _Period = std::__1::ratio<1, 1>, Rep2 = A] using type = decltype(std::declval() / std::declval()); ^
test.cpp:24:1: note: in instantiation of template class 'div_type_or >, A, D>' requested here using div_type_or_t = typename div_type_or::type; ^
test.cpp:48:19: note: in instantiation of template type alias 'div_type_or_t' requested here div_type_or_t, D>{}, "");
据我了解,这是因为 std::chrono::duration
的 operator/
的以下重载失败了:
template< class Rep1, class Period, class Rep2 >
duration<typename std::common_type<Rep1,Rep2>::type, Period>
constexpr operator/( const duration<Rep1, Period>& d,
const Rep2& s );
我认为由于 std::common_type
是函数签名的一部分,这将允许 SFINAE 工作并使用我自定义的 operator/
重载,从而推导出 default_t
,但显然这不起作用...
因为这适用于 libstdc++,我只想知道我的代码是否有问题(也许我不明白 SFINAE 在这种情况下的工作方式)或者这是一个 libc++ 错误?
在 libc++ 中,我们有:
template <class _Duration, class _Rep, bool = __is_duration<_Rep>::value>
struct __duration_divide_result
{
};
template <class _Duration, class _Rep2,
bool = is_convertible<_Rep2,
typename common_type<typename _Duration::rep, _Rep2>::type>::value>
struct __duration_divide_imp
{
};
template <class _Rep1, class _Period, class _Rep2>
struct __duration_divide_imp<duration<_Rep1, _Period>, _Rep2, true>
{
typedef duration<typename common_type<_Rep1, _Rep2>::type, _Period> type;
};
template <class _Rep1, class _Period, class _Rep2>
struct __duration_divide_result<duration<_Rep1, _Period>, _Rep2, false>
: __duration_divide_imp<duration<_Rep1, _Period>, _Rep2>
{
};
template <class _Rep1, class _Period, class _Rep2>
inline _LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR
typename __duration_divide_result<duration<_Rep1, _Period>, _Rep2>::type
operator/(const duration<_Rep1, _Period>& __d, const _Rep2& __s)
{
typedef typename common_type<_Rep1, _Rep2>::type _Cr;
typedef duration<_Cr, _Period> _Cd;
return _Cd(_Cd(__d).count() / static_cast<_Cr>(__s));
}
所以 std::common_type<_Rep1, _Rep2>::type
,
他们使用 __duration_divide_result<duration<_Rep1, _Period>, _Rep2 /*, false*/>
,
实例化 __duration_divide_imp<duration<_Rep1, _Period>, _Rep2
/*, is_convertible<_Rep2, typename common_type<_Rep1, _Rep2>::type>::value*/>
该用法是一个硬错误。
我会说 libc++ 中的实现在这方面是不正确的。