Назначение указателя на функцию с переменными аргументами с помощью пакета параметров - PullRequest
3 голосов
/ 22 мая 2019

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

Базовая конструкция, которую я пытался использовать, выглядит следующим образом

template <typename... Args>
using ArgsFuncPointer = void(*)(Args...);

template<typename... Args> void varArgsFunc(Args&&... args) {  }

{
    ArgsFuncPointer<int, float> funcPointer = varArgsFunc;   
    funcPointer(1, 2.0);
}

Проблема в том, что varArgsFunc невозможно преобразовать в ArgsFuncPointer<int, float>

См. coliru для (не) рабочего примера.

В конечном итоге я хотел бы иметь возможность сделать что-то вроде:

template <typename... Args> class Foo
{
public:
    Foo(Args&&... args)
    {
        func(args);
    }

    VarArgsFuncPointer func;
}

UPDATE

Оказывается, причина, по которой он не будет компилироваться, заключается в тонкой разнице в сигнатуре между ArgsFuncPointer и varArgsFunc. При ArgsFuncPointer пакет параметров передается по ссылке rvalue, тогда как при varArgsFunc пакет параметров передается по значению.

Это работает:

template <typename... Args>
using ArgsFuncPointer = void(*)(Args&&...);

template<typename... Args> void varArgsFunc(Args&&... args) {  }

{
    ArgsFuncPointer<int, float> funcPointer = varArgsFunc;   
    funcPointer(1, 2.0);
}

Рабочий пример здесь

Ответы [ 2 ]

4 голосов
/ 22 мая 2019

Проблема в том, что varArgsFunc является шаблоном , а не определенной функцией, но ArgsFuncPointer<int, float> является указателем на конкретную функцию.

Не проверено, но вы должны иметь возможность указать фактический экземпляр функции, указав аргументы ее шаблона:

ArgsFuncPointer<int, float> funcPointer = varArgsFunc<int, float>;
//                                                   ^^^^^^^^^^^^
//                                Must specify template arguments

С другой стороны, я рекомендую вам использовать std::function вместо указателей на функции, не являющиеся членами . Это позволит вам использовать std::bind или lambdas или почти любой вызываемый объект.

Использование std::function будет очень похоже на то, что у вас есть сейчас:

template <typename... Args>
using ArgsFuncPointer = std::function<void(Args...)>;

Тогда используя лямбду, вы можете сделать что-то вроде

ArgsFuncPointer<int, float> funcPointer = [](int i, float f)
{
    varArgsFunc(i, f);  // Call the real function
};
1 голос
/ 22 мая 2019

Вы что-то вроде

template <typename... Args>
using ArgsFuncPointer = void(*)(Args...);

template <typename... Args> class Foo
{
public:
    Foo(Args&&... args)
    {
        func(std::forward<Args>(args)...);
    }

    ArgsFuncPointer<Args...> func;
};

Пакеты должны быть расширены при использовании в выражениях.

...