How to determine that a member function has a specific function by taking specific arguments?

I already have SFINAE code that determines if a given member function exists and can accept an instance of a certain type.

I am trying to detect when there is a specific member function that accepts, since this is a non-LINK argument.

Code example

template<typename TYPE_T>
class HasSwapMemberImpl
{
    /*
     * This uses the compilers type deduction magic to ensure that there SOME swap function
     * that 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 { };

This works for a few dozen test cases that I wrote, so I don't need help here.

Instead, I try to detect a situation like this:

struct NonReferenceSwap
{
    void swap(NonReferenceSwap) {}
};

struct ReferenceSwap
{
    void swap(ReferenceSwap &) {}
};

I need a MetaHelperType metaprogramming assistant, such that MetaHelperType inherits from boost :: true_type, but MetaHelperType forces the compiler to fail with a message like "Swap functions must accept reference arguments!"

Or in other words:

MetaHelperType<ReferenceSwap>; // IS A boost::true_type
MetaHelperType<NoSwapFunction>; // IS A boost::false_type
MetaHelperType<NonReferenceSwap>; // Compiler error

? , foo.swap(bar), bar . C++, , , , - 2 .

Visual Studio 2010, ++ 11. , , , , .

? , ++ ? ++ 11, ++ 14, ++ 17?

+4
2

:

#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;

+2

, . 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
0

Source: https://habr.com/ru/post/1606921/


All Articles