C++ 如何检测成员函数具有特定的函数,使用特定的参数?

C++ 如何检测成员函数具有特定的函数,使用特定的参数?,c++,c++11,sfinae,C++,C++11,Sfinae,我已经有了SFINAE代码,它可以检测给定成员函数是否存在,并可以接受特定类型的实例 我试图检测何时有一个特定的成员函数将非引用作为参数 示例代码 template<typename TYPE_T> class HasSwapMemberImpl { /* * This uses the compilers type deduction magic to ensure that there's SOME swap function * that's a m

我已经有了SFINAE代码,它可以检测给定成员函数是否存在,并可以接受特定类型的实例

我试图检测何时有一个特定的成员函数将非引用作为参数

示例代码

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 { };
我想要一些元编程助手MetaHelperType,这样MetaHelperType就继承了boost::true_type,但MetaHelperType会导致编译器出错,并显示一条消息,如“交换函数必须使用引用参数!”

或者,换句话说:

MetaHelperType<ReferenceSwap>; // IS A boost::true_type
MetaHelperType<NoSwapFunction>; // IS A boost::false_type
MetaHelperType<NonReferenceSwap>; // Compiler error
MetaHelperType;//是boost::true\u类型
MetaHelperType;//是boost::false\u类型
MetaHelperType;//编译错误
我为什么要这个?试图调用foo.swap(bar)是一个毫无意义的概念,此时bar将作为值传递。我的组织有很多新手C++程序员,我们希望能够立即发现这个错误,而不是发现有人忘记了& 2个月后。 我使用的是VisualStudio2010,因此并非所有的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));
#包括
#定义\u具有\u签名(traitsName、funcName、签名)\
模板\
类traitsName\
{                                                                       \
私人:\
模板结构助手\
模板\
静态标准::uint8_t检查(helper*)\
模板静态标准::uint16_t检查(…)\
公众:\
静止的\
constexpr bool value=sizeof(检查(0))==sizeof(标准::uint8_t)\
}
定义有签名(有引用交换,T::交换,无效(T::*)(T&);
定义有签名(有值交换,T::交换,无效(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;
模板
结构元帮助器类型\u impl
{
静态\u断言(!具有\u值\u交换::值,
T::swap的实现不正确
“签名应该是无效的T::swap(T&)而不是T::swap(T)”;
使用type=std::conditional\u t;
};
模板
使用MetaHelperType=typename MetaHelperType_impl::type;

获取swap的成员函数指针,并将其转换为所需的正确签名。如果可以检查此强制转换是否失败,请与enable_一起:

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 {};
模板
结构交换_签名{typedef void(T::*type)(T&);};
模板
结构是可交换的:std::false_类型{};
模板
结构是可交换的::类型>:std::true_类型{};
然后您可以测试:

is_swappable<ReferenceSwap>::value // true
is_swappable<NonReferenceSwap>::value // false
是否可交换::value//true
是可交换的::值//false

这可以确定存在T::swap(T)和T::swap(T&)的情况?几天来,我一直在处理这段代码,我使用了这项技术,但无法让它检测出差异。我遗漏了什么吗?@jonesmz:是的,它检查的是确切的签名。大多数情况下,这是一个太强的要求(在我的示例中,
swap
需要返回
void
),因为cv限定符应该匹配,返回类型应该匹配,这在泛型代码中不是必需的。OT:
*static_cast(nullptr)
可以被
std::declval()
替换。在我的环境中不需要。我们使用VS2010+STLPort。STLPort不支持C++11标准库内容。(我们使用的是过时版本的boost)很抱歉在原始帖子中没有提到这一点。
is_swappable<ReferenceSwap>::value // true
is_swappable<NonReferenceSwap>::value // false