簡體   English   中英

如何檢查成員函數是否具有const重載?

[英]How can I check whether a member function has const overload?

可以說我有

struct foo {
    void ham() {}
    void ham() const {}
};

struct bar {
    void ham() {}
};

假設我有一個模板化函數,我可以判斷給定類型是否具有ham的常量過載?

#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_ham_const, T::ham, void (T::*)() const);

接着

static_assert(has_ham_const<foo>::value, "unexpected");
static_assert(!has_ham_const<bar>::value, "unexpected");

演示

檢測器(如is_detected ):

template <typename...>
using void_t = void;

template <typename T, template <typename> class D, typename = void>
struct detect : std::false_type {};

template <typename T, template <typename> class D>
struct detect<T, D, void_t<D<T>>> : std::true_type {};

樣本成員驗證者:

template <typename T>
using const_ham = decltype(std::declval<const T&>().ham());

測試:

static_assert(detect<foo, const_ham>::value, "!");
static_assert(!detect<bar, const_ham>::value, "!");

DEMO

SFINAE一遍又一遍。 這是另一個未指定返回類型的選項,但允許您指定參數。

(為了比較:@ Jarod42的方法檢查確切的簽名,返回類型+參數,其他void_t表達式sfinae到目前為止只檢查是否可以調用ham() 。)

此外,它適用於當前的MSVC 2015 Update 1版本(與通常的void_t內容不同)。

template<typename V, typename ... Args>
struct is_callable_impl
{
    template<typename C> static constexpr auto test(int) -> decltype(std::declval<C>().ham(std::declval<Args>() ...), bool{}) { return true; }
    template<typename> static constexpr auto test(...) { return false; }
    static constexpr bool value = test<V>(int{});
    using type = std::integral_constant<bool, value>;
};

template<typename ... Args>
using is_callable = typename is_callable_impl<Args...>::type;

用它作為

struct foo
{
    void ham() {}
    void ham() const {}
    int ham(int) const {}
};

int main()
{
     std::cout
      <<is_callable<foo>::value                //true
      <<is_callable<const foo>::value          //true
      <<is_callable<const foo, int>::value     //true
      <<is_callable<const foo, double>::value  //also true, double is converted to int
      <<is_callable<const foo, std::string>::value  //false, can't call foo::ham(std::string) const
      <<std::endl;
}

Coliru演示

然而,對於“最新的”sfinae的東西,我建議你看看boost.hana

另一種選擇是模擬void_t (在C ++ 17中正式出現),它使用表達式SFINAE來確保你的函數在const實例上是可調用的,而不管它的返回類型如何。

#include <iostream>
#include <type_traits>

struct Foo
{
    void ham() const;
    void ham();
};

struct Bar {
    void ham() {}
};

template<typename...>
using void_t = void;

template<typename C, typename = void>
struct has_const_ham: std::false_type{};

template<typename C> // specialization, instantiated when there is ham() const
struct has_const_ham<C, void_t<decltype(std::declval<const C&>().ham())>> : 
    std::true_type{};

int main()
{
    std::cout << std::boolalpha;
    std::cout << has_const_ham<Foo>::value << std::endl;
    std::cout << has_const_ham<Bar>::value << std::endl;
}

編輯

如果要強制執行返回類型,則從std::is_same派生std::is_same ,如

template<typename C> // specialization, instantiated when there is ham() const
struct has_const_ham<C, void_t<decltype(std::declval<const C&>().ham())>> : 
    std::is_same<decltype(std::declval<const C&>().ham()), void> // return must be void
{}; 

住在Coliru

這是一個沒有宏的解決方案,它也不關心返回類型:

template <typename T>
struct is_well_formed : std::true_type
{
};

template <typename T, typename = void>
struct has_const_ham : std::false_type
{
};

template <typename T>
struct has_const_ham<T,
                     typename std::enable_if<is_well_formed<decltype(
                         std::declval<const T&>().ham())>::value>::type>
    : std::true_type
{
};


static_assert(has_const_ham<foo>::value, "oops foo");
static_assert(!has_const_ham<bar>::value, "oops bar");

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM