【问题标题】:C++ SFINAE and numeric conversions (coercion)C++ SFINAE 和数字转换(强制)
【发布时间】:2017-11-29 03:03:35
【问题描述】:

我现在尝试学习 SFINAE,但似乎我遇到了强制问题,我该怎么做才能使 hasRead<Y>hasRead<Z> 失败,因为方法参数不对应于 std::uint16_t

我加入了我的代码,看看可以做些什么来让它像我想要的那样工作!

提前致谢:)

#include <cstdint>
#include <iostream>
#include <utility>

template<typename Class>
struct hasRead {
private:
    template<typename T>
    static constexpr auto check(T *) -> typename std::is_same<
        decltype(std::declval<T>().read(std::declval<uint16_t>())), uint8_t>::type;


    template<typename>
    static constexpr std::false_type check(...);

    typedef decltype(check<Class>(0)) type;

public:
    static constexpr bool value = type::value;
};

struct X {
    uint8_t read(uint16_t x) { return 3; }
};

struct Y {
    uint8_t read(uint8_t x) { return 3; }
};

struct Z {
    uint8_t read(int64_t x) { return 3; }
};

static_assert(hasRead<X>, "");
static_assert(hasRead<Y>, "");
static_assert(hasRead<Z>, "");

【问题讨论】:

    标签: c++ c++11 templates sfinae


    【解决方案1】:

    我想提供一种更现代的方法来检测成员函数的存在,称为detection idiom

    精简版只需要 C++11。它更简洁,这样做也提供了检测 template 成员函数的能力(max66's version 没有)。

    template<typename T, uint8_t (T::*)(uint16_t) = &T::read>
    using detectRead = void;
    
    template<typename, typename = void>
    struct hasRead : std::false_type {};
    
    template<typename T>
    struct hasRead<T, detectRead<T>> : std::true_type {};
    

    你用同样的方式

    struct A { uint8_t read(uint16_t); };
    struct B {};
    struct C { uint8_t read(uint32_t); };
    struct D
    {
        template<typename T, typename U>
        U read(T);
    };
    
    void test()
    {
        static_assert(hasRead<A>::value, "");  // OK
        static_assert(hasRead<B>::value, "");  // fails
        static_assert(hasRead<C>::value, "");  // fails
        static_assert(hasRead<D>::value, "");  // OK
    }
    

    Live

    †​​为了迂腐,SFINAE in partial specializations is ill-formed in C++11 due to wording defects的用法

    【讨论】:

    • 我通过一些研究得到了这样的解决方案,我发现我可以更简洁:godbolt.org/g/BTzufc
    • 太棒了!非常简单优雅。
    【解决方案2】:

    我想您可以检查 (1) 函数存在并接受 uint16_t 并且 (2) 它的类型是 uint8_t(T::*)(uint16_t)

    类似

    template <typename Class>
    struct hasRead
     {
       private:
          template <typename T>
          static constexpr auto check (T * t)
             -> decltype( t->read(uint16_t{}),
                std::is_same<decltype(&T::read), uint8_t(T::*)(uint16_t)>{} );
    
          template<typename>
          static constexpr std::false_type check(...);
    
       public:
          static constexpr bool value = decltype(check<Class>(nullptr))::value;
     };
    

    以下是完整的编译示例

    #include <cstdint>
    #include <iostream>
    #include <utility>
    
    template <typename Class>
    struct hasRead
     {
       private:
          template <typename T>
          static constexpr auto check (T * t)
             -> decltype( t->read(uint16_t{}),
                std::is_same<decltype(&T::read), uint8_t(T::*)(uint16_t)>{} );
    
          template<typename>
          static constexpr std::false_type check(...);
    
       public:
          static constexpr bool value = decltype(check<Class>(nullptr))::value;
     };
    
    struct X { uint8_t read(uint16_t x) { return 3; } };
    struct Y { uint8_t read(uint8_t x) { return 3; } };
    struct Z { uint8_t read(int64_t x) { return 3; } };
    struct A { };
    
    int main()
     {
       static_assert( true  == hasRead<X>::value, "" );
       static_assert( false == hasRead<Y>::value, "" );
       static_assert( false == hasRead<Z>::value, "" );
       static_assert( false == hasRead<A>::value, "" );
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-19
      • 1970-01-01
      相关资源
      最近更新 更多