C++ SFINAE 和数值转换(强制)

C++ SFINAE and numeric conversions (coercion)

我现在正在尝试学习 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>, "");

我想您可以检查 (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, "" );
 }

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

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

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

†迂腐,

的用法