C ++ 11: Расчет типов параметров переменных функций - PullRequest
4 голосов
/ 13 ноября 2011

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

В невариантном случае, рассматривая однопараметрические функции для простоты, есть два способа сделать это: вы можете позволить функции переадресации принять аргумент произвольного типа и попытаться вызвать функцию форварди с ним,и компилятор будет жаловаться во время расширения шаблона, если он окажется несовместимым;или вы можете использовать decltype и различные другие механизмы, чтобы выяснить, какой тип параметра ожидает функция forwardee, и явно требовать аргумент этого типа.Я не знаю, есть ли какая-либо принятая терминология для них, поэтому я буду называть их «сквозной» и «прямой».

Метод сквозной передачи напрямую обобщает функции с произвольным числомпараметров, но метод с открытым исходным кодом - нет.

#include <iostream>

template<typename T, typename Arg>
void pass_through_1(Arg arg)
{
    T::f(arg);
}

template<typename T> struct arg_of_1;

template<typename Ret, typename Arg>
struct arg_of_1<Ret (Arg)>
{
    typedef Arg type;
};

template<typename T>
void up_front_1(typename arg_of_1<decltype(T::f)>::type arg)
{
    T::f(arg);
}

template<typename T, typename... Args>
void pass_through_var(Args... args)
{
    T::f(args...);
}

template<typename T> struct args_of_var;

template<typename...> struct type_list;

template<typename Ret, typename... Args>
struct args_of_var<Ret (Args...)>
{
    // typedef Args... type; // can't do this
    typedef type_list<Args...> type;
};

// template<typename T>
// void up_front_var(typename args_of_var<decltype(T::f)>::type... args) // can't do this
// {
//     T::f(args...);
// }

struct test  
{ 
    static void f(int x) { std::cout << x*9 << std::endl; }
};

int main(int, char**)
{
    pass_through_1<test>(7);
    up_front_1<test>(8);
    pass_through_var<test>(9);
    // up_front_var<test>(10);
    return 0;
}

Проблема в том, что пакетам параметров не разрешается быть автономными, только в качестве аргументов шаблона, и если вы заключаете их в вмещающий шаблоннет возможности развернуть и распаковать их на месте, только путем сопоставления с шаблоном.

У «впереди» есть некоторые преимущества, такие как улучшение самодокументирования и лучшая поддержка вывода типов (up_front можетсам будет дешифрован).Есть ли способ заставить его работать в вариационном случае?(Конечно, вы можете использовать std :: tuple, но это довольно неудовлетворительно.)

Ответы [ 2 ]

1 голос
/ 13 ноября 2011

Нет ничего лучше, чем записать вопрос, чтобы вы поняли ответ.

Вот один из способов:

template<typename T, typename Args = typename args_of_var<decltype(T::f)>::type>
struct up_front_var;

template<typename T, typename... Args>
struct up_front_var<T, type_list<Args...>>
{
    static void forward(Args... args)
    {
        T::f(args...);
    }
};

Я не думаю, что есть способ сделать верхний уровеньработать из этого (вы снова сталкиваетесь с исходной проблемой), но, возможно, это не так уж и плохо.

Все равно был бы рад видеть другие решения.

0 голосов
/ 17 июня 2016

Возможно, я не правильно понимаю вопрос, но вы всегда можете опустить типы аргументов и позволить компилятору выводить их.

/* declare */
template<typename T, typename... Args>
void up_front_var(Args... args)
{
    T::f(std::forward<Args>(args)...); // need std::forward to correctly handle lvalue/rvalue references
}

/* an example */
class Test {
public:
    static void f(const char* fmt, int a, int b);
};

void Test::f(const char* fmt, int a, int b)
{
    printf(fmt, a, b); 
}


int main()
{
    up_front_var<Test>("testing %u, %u", 1, 2); // no need to specify arguments here
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...