Информация об изменениях

Сообщение Re: Есть ли метод у класса - HasMethod - старая тема от 10.11.2019 19:24

Изменено 10.11.2019 23:40 rg45

Re: Есть ли метод у класса - HasMethod - старая тема
Здравствуйте, Molchalnik, Вы писали:

M>Искал на нашем форуме SFINAE фишку по определению наличия класса в методе — нашёл только очень старую тему, написанную по старому стандарту, и которую крайне трудно адаптировать, потому что проще для каждого нового метода написать с нуля.


Ну и я свои пять копеек вставлю

http://coliru.stacked-crooked.com/a/5e7c5dcd2b844e6b

Собсно инструмент:

#define ENABLE_HAS_METHOD(method)     template <typename, typename = void>     struct has_method_##method : std::false_type {};     template <typename Obj, typename...Args>     struct has_method_##method<std::tuple<Obj, Args...>,         std::void_t<decltype(std::declval<Obj>().method(std::declval<Args>()...))>> : std::true_type {};

#define HAS_METHOD(method, ...) (has_method_##method<std::tuple<__VA_ARGS__>>::value)


И пример использования:

struct A
{
    void foo();
    void foo(int, double) const;

    template <typename...Args>
    void bar(Args&&...) const;

    void baz() &;
    void baz(const std::string&) const&;
    void baz(const std::string&) && = delete;
    void baz(int) &&;
};

ENABLE_HAS_METHOD(foo)
ENABLE_HAS_METHOD(bar)
ENABLE_HAS_METHOD(baz)

int main()
{
    std::cout << std::boolalpha;

    std::cout << "--- foo ---" << std::endl;
    std::cout << HAS_METHOD(foo, const A) << std::endl;         // false
    std::cout << HAS_METHOD(foo, A) << std::endl;               // true
    std::cout << HAS_METHOD(foo, A, int, double) << std::endl;  // true

    std::cout << "--- bar ---" << std::endl;
    std::cout << HAS_METHOD(bar, const A) << std::endl;         // true
    std::cout << HAS_METHOD(bar, A) << std::endl;               // true
    std::cout << HAS_METHOD(bar, A, double&, int) << std::endl;               // true
    std::cout << HAS_METHOD(bar, A, std::string, const std::string&, std::string&, std::string&) << std::endl;  // true
    std::cout << HAS_METHOD(bar, volatile A, int) << std::endl;         // false

    std::cout << "--- baz ---" << std::endl;
    std::cout << HAS_METHOD(baz, A&) << std::endl;         // true
    std::cout << HAS_METHOD(baz, A&, std::string) << std::endl;         // true
    std::cout << HAS_METHOD(baz, const A&, std::string) << std::endl;         // true
    std::cout << HAS_METHOD(baz, A, int) << std::endl;         // true

    std::cout << HAS_METHOD(baz, const A&) << std::endl;         // false
    std::cout << HAS_METHOD(baz, A, std::string) << std::endl;         // false
    std::cout << HAS_METHOD(baz, A&&, std::string) << std::endl;         // false
    std::cout << HAS_METHOD(baz, const A&, int) << std::endl;         // false

}
Re: Есть ли метод у класса - HasMethod - старая тема
Здравствуйте, Molchalnik, Вы писали:

M>Искал на нашем форуме SFINAE фишку по определению наличия класса в методе — нашёл только очень старую тему, написанную по старому стандарту, и которую крайне трудно адаптировать, потому что проще для каждого нового метода написать с нуля.


Ну и я свои пять копеек вставлю

http://coliru.stacked-crooked.com/a/9342a5dfe9074fa7

Собсно инструмент:

#define ENABLE_HAS_METHOD(method)     template <typename, typename = void>     struct has_method_##method : std::false_type {};     template <typename Obj, typename...Args>     struct has_method_##method<std::tuple<Obj, Args...>,         std::void_t<decltype(std::declval<Obj>().method(std::declval<Args>()...))>> : std::true_type {};

#define HAS_METHOD(method, ...) (has_method_##method<std::tuple<__VA_ARGS__>>::value)


И пример использования:

struct A
{
    void foo();
    void foo(int, double) const;

    template <typename...Args>
    void bar(Args&&...) const;

    void baz() &;
    void baz(const std::string&) const&;
    void baz(const std::string&) && = delete;
    void baz(int) &&;
};

ENABLE_HAS_METHOD(foo)
ENABLE_HAS_METHOD(bar)
ENABLE_HAS_METHOD(baz)

int main()
{
    std::cout << std::boolalpha;

    #define CHECK(cond) (std::cout << #cond << ": " << cond << std::endl)
    
    std::cout << "--- foo ---" << std::endl;
    CHECK(HAS_METHOD(foo, const A));         // false
    CHECK(HAS_METHOD(foo, A));               // true
    CHECK(HAS_METHOD(foo, A, int, double));  // true

    std::cout << "--- bar ---" << std::endl;
    CHECK(HAS_METHOD(bar, const A));         // true
    CHECK(HAS_METHOD(bar, A));               // true
    CHECK(HAS_METHOD(bar, A, double&, int)); // true
    CHECK(HAS_METHOD(bar, A, std::string, const std::string&, std::string&, std::string&));  // true
    CHECK(HAS_METHOD(bar, volatile A, int)); // false

    std::cout << "--- baz ---" << std::endl;
    CHECK(HAS_METHOD(baz, A&));                     // true
    CHECK(HAS_METHOD(baz, A&, std::string));        // true
    CHECK(HAS_METHOD(baz, const A&, std::string));  // true
    CHECK(HAS_METHOD(baz, A, int));                 // true

    CHECK(HAS_METHOD(baz, const A&));           // false
    CHECK(HAS_METHOD(baz, A, std::string));     // false
    CHECK(HAS_METHOD(baz, A&&, std::string));   // false
    CHECK(HAS_METHOD(baz, const A&, int));      // false
}