具有特征检测部门的SFINAE问题

时间:2017-09-07 16:20:39

标签: c++ c++14 libc++

我有以下特征来检测两个类型是否可以整除,并返回结果操作类型或其他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;

当我尝试使用不可分割的std::chrono::duration类型时,这适用于libstdc ++,但不适用于libc ++,例如:

struct A { };

div_type_or_t<std::chrono::seconds, A, int> b;

我收到以下错误:

  

/库/开发商/ CommandLineTools的/ usr /包括/ C ++ / V1 /计时:764:81:   错误:没有名为'type'的类型         '的std :: __ 1 :: common_type'                             typename common_type :: type&gt; :: value&gt;                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~ ^ ~~~

     

/库/开发商/ CommandLineTools的/ usr /包括/ C ++ / V1 /计时:777:7:   注意:在默认参数的实例化中         '__duration_divide_imp&gt;,A&gt;'需要在这里       :__ duration_divide_imp,_Rep2&gt;         ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~&gt;

     

/库/开发商/ CommandLineTools的/ usr /包括/ C ++ / V1 /计时:784:10:   注意:在模板类的实例化中         'std :: __ 1 :: chrono :: __ duration_divide_result&gt;,A,false&gt;'         这里请求typename __duration_divide_result,_Rep2&gt; :: type            ^

     

test.cpp:16:46:注意:将推导出的模板参数替换为函数模板'operator /'[with _Rep1 = long         long,_Period = std :: __ 1 :: ratio&lt; 1,1&gt;, Rep2 = A]       使用类型 = decltype(std :: declval()/ std :: declval());                                                ^

     

test.cpp:24:1:注意:在模板类的实例化中   'div_type_or&gt;,A,D&gt;'这里使用div_type_or_t = typename div_type_or :: type; ^

     

TEST.CPP:48:19:   注意:在模板类型别名“div_type_or_t”的实例化中   这里要求                     div_type_or_t,D&gt; {},“”);

据我了解,这是因为operator/ std::chrono::duration的以下重载失败:

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 ++错误?

1 个答案:

答案 0 :(得分:3)

在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 ++中的实现是不正确的。