如何检测一个成员函数是否具有特定的功能,接受特定的参数?
How to detect that a member function has specific function, taking specific arguments?
我已经有 SFINAE 代码来检测给定的成员函数是否存在并且可以接受特定类型的实例。
我正在尝试检测何时有一个特定的成员函数将 NON-REFERENCE 作为参数。
示例代码
template<typename TYPE_T>
class HasSwapMemberImpl
{
/*
* This uses the compilers type deduction magic to ensure that there's SOME swap function
* that's a member of CLASS_T, that can be passed an instance of CLASS_T, in some fashion.
* This doesn't determine that the argument for the function is a reference.
*/
template <typename CLASS_T>
static auto test_compatible_swap_function_exists(CLASS_T * p) -> decltype(p->swap(*static_cast<CLASS_T*>(nullptr)), boost::true_type());
/*
* If no substitutions can satisfy p->swap(*static_cast<CLASS_T*>(nullptr)
* we end up here as fallback.
*/
template<typename>
static boost::false_type test_compatible_swap_function_exists(...);
public:
typedef decltype(test_compatible_swap_function_exists<TYPE_T>(nullptr)) type;
static const bool value = type::value;
};
/**
* \brief This MetaProgramming helper class determines if there exists a method named "swap" in the ARG_T type, that takes ARG_T as an argument.
*
* If ARG_T.swap(ARG_T) is a valid function, then HasSwapMember inherits from boost::true_type. Else it inherits from boost::false_type.
*/
template<typename ARG_T>
struct HasSwapMember : public HasSwapMemberImpl<ARG_T>::type { };
这适用于我编写的几十个测试用例,因此我在这里不需要任何帮助。
相反,我要做的是检测这样的情况
struct NonReferenceSwap
{
void swap(NonReferenceSwap) {}
};
struct ReferenceSwap
{
void swap(ReferenceSwap &) {}
};
我想要一些元编程助手,MetaHelperType,这样 MetaHelperType 继承自 boost::true_type,但 MetaHelperType 导致编译器出错并显示类似 "Swap functions must take reference arguments!"
的消息
或者,换句话说:
MetaHelperType<ReferenceSwap>; // IS A boost::true_type
MetaHelperType<NoSwapFunction>; // IS A boost::false_type
MetaHelperType<NonReferenceSwap>; // Compiler error
我为什么要这个?当 bar 将作为值传递时,尝试调用 foo.swap(bar) 是一个无意义的概念。我的组织有很多新手 c++ 程序员,我们希望能够立即发现这个错误,而不是在 2 个月后发现有人忘记了 &。
我使用的是 Visual Studio 2010,因此并非所有 c++11 功能都可用。不过,上面的代码确实可以正常工作,所以至少这些功能可以按预期工作。
这可能吗?如果是这样,需要什么最低版本的 C++? C++11、C++14、C++17?
我使用以下方法进行精确的签名检查:
#include <cstdint>
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature) \
template <typename U> \
class traitsName \
{ \
private: \
template<typename T, T> struct helper; \
template<typename T> \
static std::uint8_t check(helper<signature, &funcName>*); \
template<typename T> static std::uint16_t check(...); \
public: \
static \
constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
}
DEFINE_HAS_SIGNATURE(has_ref_swap, T::swap, void (T::*)(T&));
DEFINE_HAS_SIGNATURE(has_value_swap, T::swap, void (T::*)(T));
然后,您可以编写您的辅助检查:
template <typename T>
struct MetaHelperType_impl
{
static_assert(!has_value_swap<T>::value,
"Incorrect implementation of T::swap, "
"signature should be void T::swap(T&) instead of T::swap(T)");
using type = std::conditional_t<has_ref_swap<T>::value,
boost::true_type,
boost::false_type>;
};
template <typename T>
using MetaHelperType = typename MetaHelperType_impl<T>::type;
获取交换的成员函数指针并将其转换为您期望的正确签名。与 enable_if 一起,您可以检查此转换是否失败:
template <typename T>
struct swap_signature { typedef void(T::*type)(T&); };
template <typename T, typename = void>
struct is_swappable : std::false_type {};
template <typename T>
struct is_swappable<T,typename std::enable_if<std::is_member_function_pointer<
decltype(static_cast<typename swap_signature<T>::type>(&T::swap))>::value>::type> : std::true_type {};
那你可以测试一下:
is_swappable<ReferenceSwap>::value // true
is_swappable<NonReferenceSwap>::value // false
我已经有 SFINAE 代码来检测给定的成员函数是否存在并且可以接受特定类型的实例。
我正在尝试检测何时有一个特定的成员函数将 NON-REFERENCE 作为参数。
示例代码
template<typename TYPE_T>
class HasSwapMemberImpl
{
/*
* This uses the compilers type deduction magic to ensure that there's SOME swap function
* that's a member of CLASS_T, that can be passed an instance of CLASS_T, in some fashion.
* This doesn't determine that the argument for the function is a reference.
*/
template <typename CLASS_T>
static auto test_compatible_swap_function_exists(CLASS_T * p) -> decltype(p->swap(*static_cast<CLASS_T*>(nullptr)), boost::true_type());
/*
* If no substitutions can satisfy p->swap(*static_cast<CLASS_T*>(nullptr)
* we end up here as fallback.
*/
template<typename>
static boost::false_type test_compatible_swap_function_exists(...);
public:
typedef decltype(test_compatible_swap_function_exists<TYPE_T>(nullptr)) type;
static const bool value = type::value;
};
/**
* \brief This MetaProgramming helper class determines if there exists a method named "swap" in the ARG_T type, that takes ARG_T as an argument.
*
* If ARG_T.swap(ARG_T) is a valid function, then HasSwapMember inherits from boost::true_type. Else it inherits from boost::false_type.
*/
template<typename ARG_T>
struct HasSwapMember : public HasSwapMemberImpl<ARG_T>::type { };
这适用于我编写的几十个测试用例,因此我在这里不需要任何帮助。
相反,我要做的是检测这样的情况
struct NonReferenceSwap
{
void swap(NonReferenceSwap) {}
};
struct ReferenceSwap
{
void swap(ReferenceSwap &) {}
};
我想要一些元编程助手,MetaHelperType,这样 MetaHelperType 继承自 boost::true_type,但 MetaHelperType 导致编译器出错并显示类似 "Swap functions must take reference arguments!"
的消息或者,换句话说:
MetaHelperType<ReferenceSwap>; // IS A boost::true_type
MetaHelperType<NoSwapFunction>; // IS A boost::false_type
MetaHelperType<NonReferenceSwap>; // Compiler error
我为什么要这个?当 bar 将作为值传递时,尝试调用 foo.swap(bar) 是一个无意义的概念。我的组织有很多新手 c++ 程序员,我们希望能够立即发现这个错误,而不是在 2 个月后发现有人忘记了 &。
我使用的是 Visual Studio 2010,因此并非所有 c++11 功能都可用。不过,上面的代码确实可以正常工作,所以至少这些功能可以按预期工作。
这可能吗?如果是这样,需要什么最低版本的 C++? C++11、C++14、C++17?
我使用以下方法进行精确的签名检查:
#include <cstdint>
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature) \
template <typename U> \
class traitsName \
{ \
private: \
template<typename T, T> struct helper; \
template<typename T> \
static std::uint8_t check(helper<signature, &funcName>*); \
template<typename T> static std::uint16_t check(...); \
public: \
static \
constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
}
DEFINE_HAS_SIGNATURE(has_ref_swap, T::swap, void (T::*)(T&));
DEFINE_HAS_SIGNATURE(has_value_swap, T::swap, void (T::*)(T));
然后,您可以编写您的辅助检查:
template <typename T>
struct MetaHelperType_impl
{
static_assert(!has_value_swap<T>::value,
"Incorrect implementation of T::swap, "
"signature should be void T::swap(T&) instead of T::swap(T)");
using type = std::conditional_t<has_ref_swap<T>::value,
boost::true_type,
boost::false_type>;
};
template <typename T>
using MetaHelperType = typename MetaHelperType_impl<T>::type;
获取交换的成员函数指针并将其转换为您期望的正确签名。与 enable_if 一起,您可以检查此转换是否失败:
template <typename T>
struct swap_signature { typedef void(T::*type)(T&); };
template <typename T, typename = void>
struct is_swappable : std::false_type {};
template <typename T>
struct is_swappable<T,typename std::enable_if<std::is_member_function_pointer<
decltype(static_cast<typename swap_signature<T>::type>(&T::swap))>::value>::type> : std::true_type {};
那你可以测试一下:
is_swappable<ReferenceSwap>::value // true
is_swappable<NonReferenceSwap>::value // false