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
}
†迂腐,
的用法
我现在正在尝试学习 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
}
†迂腐,