Определить, определена ли функция / оператор / метод с определенной сигнатурой - PullRequest
0 голосов
/ 01 марта 2020

Исходя из этого вопроса, как мы можем обнаружить (во время компиляции), если определена функция / оператор / метод, имеющий определенную сигнатуру?

Из связанного вопроса и взгляда на cppreference about std :: void_t мы можем написать (C ++ 17 впереди)

#include<iostream>
#include<type_traits>
#include<utility>

class X { public: int someFunc() const{ return 9; } };
class Y{};

template<typename, typename = std::void_t<>> struct Has_someFunc
    : std::false_type{};
template<typename T> struct Has_someFunc<T, std::void_t<decltype(std::declval<T>().someFunc())>>
    : std::true_type{};

template<typename T>
void f(const T& v){
    if constexpr(Has_someFunc<T>::value)
        std::cout << "has someFunc()\n";
    else
        std::cout << "has NOT someFunc()\n";
}

int main()
{
    std::cout << "X "; f(X{});
    std::cout << "Y "; f(Y{});

    return 0;
}

, который печатает

X has someFunc()
Y has NOT someFunc()

, но что если мы хотим проверить тип на иметь someFunc не только для определения, но и для определенной сигнатуры?

Хотя я использую C ++ 17, ответы в любой другой версии стандарта приветствуются.

1 Ответ

1 голос
/ 01 марта 2020

Если вы намереваетесь проверить, есть ли у типа метод someFunc(), который совместим (доступен с) для данной подписи), и вернуть данный тип, вы можете изменить свой код следующим образом

#include<iostream>
#include<type_traits>
#include<utility>

class X
 { public: int someFunc (int, long) const { return 9; } };

class Y
 { };

template <typename, typename = void>
struct Has_someFunc : public std::false_type
 { };

template <typename T, typename RType, typename ... Args>
struct Has_someFunc<std::tuple<T, RType, Args...>, std::enable_if_t<
   std::is_same_v<RType, 
      decltype(std::declval<T>().someFunc(std::declval<Args>()...))>>>
    : public std::true_type
 { };

template <typename RType, typename ... Args, typename T>
void f (T const & v)
 {
   if constexpr (Has_someFunc<std::tuple<T, RType, Args...>>::value)
      std::cout << "has someFunc()\n";
   else
      std::cout << "has NOT someFunc()\n";
 }

int main()
{
    std::cout << "X "; f<int>(X{});
    std::cout << "X "; f<int, int, long>(X{});
    std::cout << "X "; f<int, int, int>(X{});
    std::cout << "Y "; f<int>(Y{});
}

Недостаток: вы получаете "has someFun c ()" также из третьего вызова, поскольку последний аргумент (int) совместим с последним ожидаемым аргументом (long).

...