Как проверить подпись метода во время выполнения - PullRequest
0 голосов
/ 14 ноября 2018

Есть ли способ определить во время выполнения тип аргумента метода в C ++ 03?Я думаю о таком способе:

#include <cstdio>

template<class T, class U>
struct is_same {
    static const bool result = false;
};

template<class T>
struct is_same<T, T> {
    static const bool result = true;
};

template<class ToFind, class Ret, class T, class Arg>
bool hasArg1(ToFind, Ret (T::*)(Arg)){return is_same<ToFind, Arg>::result;}

template<class ToFind, class Ret, class T, class Arg1, class Arg2>
bool hasArg1(ToFind, Ret (T::*)(Arg1, Arg2)){return is_same<ToFind, Arg1>::result;}

struct A
{
    int fun1(int a){return a+1;}
};

int main() {
    std::printf("int arg1: %s\n", hasArg1(1, &A::fun1) ? "yes" : "no");
}

, но я хочу что-то вроде этого:

hasArg1<int>(&A::fun1)

вместо

hasArg1(1, &A::fun1)

1 Ответ

0 голосов
/ 14 ноября 2018

Просто удалите первый аргумент функции:

template<class ToFind, class Ret, class T, class Arg>
bool hasArg1(Ret (T::*)(Arg)){return is_same<ToFind, Arg>::result;}

template<class ToFind, class Ret, class T, class Arg1, class Arg2>
bool hasArg1(Ret (T::*)(Arg1, Arg2)){return is_same<ToFind, Arg1>::result;}

Теперь hasArg1<int>(&A::fun1) работает так, как вы хотите.

Просмотр в реальном времени

Но имейте в виду, что этот подход не будет работать, если A::fun1 перегружен.


Теперь, как было отмечено под вашим вопросом.Проверка таких вещей во время выполнения менее полезна.Обычно вы хотите, чтобы эта информация во время компиляции влияла на генерацию кода и, возможно, оптимизировалась на основе. ограничен во времени компиляции по сравнению с более поздними ревизиями, но выполнить эту проверку во время компиляции не исключено.Вот как бы вы изменили свой код, чтобы сделать это:

template<bool C, typename T = void>
struct enable_if;

template<typename T>
struct enable_if<true, T> { typedef T type; };

template<int s> struct tag { char _[s]; };

template<class ToFind>
tag<1> hasArg1(...);

template<class ToFind, class Ret, class T, class Arg>
tag<2> hasArg1(Ret (T::*)(Arg), enable_if<is_same<ToFind, Arg>::result, void>* = 0);

// Add hasArg1 overloads to support members with more arguments

#define HAS_ARG1(ToFind, member) (sizeof(hasArg1<ToFind>(member)) != sizeof(tag<1>))

Сначала мы добавим «запасную» перегрузку, которая возвращает тип с ожидаемым размером.Затем добавляем еще одну перегрузку, модифицированную по вашему.Проверка передается другому аргументу функции.Если при разрешении перегрузки проверки завершаются неудачно, аргумент неверно сформирован, а подстановка завершается неудачно, оставляя нас только с запасным вариантом, потому что SFINAE потрясающий!

Если проверка пройдена, вторая перегрузка корректна илучшее совпадение, поскольку многоточие имеют наименьший приоритет среди последовательностей преобразования в разрешении перегрузки.

Макрос добавлен для синтаксического сахара, поскольку последующие детали вводить снова и снова утомительно.Мы делаем разрешение перегрузки внутри оператора sizeof.Выбранная перегрузка через тип возврата будет отражена в сообщениях sizeof(hasArg1<ToFind>(member)).Таким образом, мы можем проверить это против sizeof(tag<1>) (запасной вариант).И поскольку sizeof является оператором времени компиляции, у нас есть постоянная времени компиляции, которая сообщает нам, является ли первый аргумент member ToFind.

И чтобы доказать, что это постоянная времени компиляции,мы можем создать экземпляр

tag<HAS_ARG1(int, &A::fun1)> test_compile_time;

Как мы делаем здесь, в GCC 4.1.2 в режиме C ++ 98 .

...