Как я могу обернуть std :: function и иметь легкий доступ к ее типам возвращаемого значения и аргумента? - PullRequest
3 голосов
/ 10 июля 2019

Я пытаюсь сделать что-то, что упрощает следующее:

#include <functional>
#include <initializer_list>
#include <vector>

template <typename Ret, typename... Args>
struct func_wrapper
{
public:
    using Func = std::function<Ret(Args...)>;

    Ret operator()(Args && ...args)
    {
        return _impl(std::forward<Args>(args)...);
    }

    void another_function(int another_arg, Args && ...args) { }
    /// and so on

private:
   Func _impl;
};

func_wrapper<void(int, float)> f;


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

<source>: In instantiation of 'struct func_wrapper<void(int, float)>':
<source>:20:32:   required from here
<source>:9:45: error: function returning a function
     using Func = std::function<Ret(Args...)>;
                                             ^
<source>:11:9: error: function returning a function
     Ret operator()(Args && ...args)

Я не уверен, что делать с этой ошибкой.Есть ли простой способ сделать то, что я хочу?

Ответы [ 2 ]

5 голосов
/ 10 июля 2019

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

template <typename Ret, typename... Args> struct func_wrapper {
     ...
};

Это означает, что ваш шаблон ожидает, что вы создадите его экземпляр, написав что-то вроде

func_wrapper<int, float> // Function taking a float and returning an int
func_wrapper<void, int, float> // Function taking a float and an int and returning void
func_wrapper<int> // Function taking no arguments and returning void

Обратите внимание, в частности, что func_wrapper<T> означает, что Ret будет T и функция не будет принимать аргументы.

В результате, когда вы пишете

func_wrapper<void(int, float)>

вы говорите "функция, представляющая что-то, что не принимает аргументов и возвращает функцию, которая принимает int и float и возвращает void", что не то, что вы хотели. Вот почему вы получаете сообщение о том, что возвращаемая функция недопустима.

2 голосов
/ 10 июля 2019

Проблема в том, что вы должны использовать частичную специализацию

template <typename>
struct func_wrapper;

template <typename Ret, typename... Args>
struct func_wrapper<Ret(Args...)>
 {
   // ...
 };

Если вы напишите

template <typename Ret, typename... Args>
struct func_wrapper
 {
   // ...
 };

объявляет f как

func_wrapper<void(int, float)> f;

у вас есть то, что Ret выводится как void(int, float), а список Args... variadic выводится как пустой список.

Итак, когда вы определяете

using Func = std::function<Ret(Args...)>;

объявление Func становится

// ............................V..........VVV  function-function type ?
using Func = std::function<void(int, float)()>;

, что дает ошибку «error: function returning the function».

Вы должны объявить func_wrapper как получающее одно имя типа

template <typename>
struct func_wrapper;

, чтобы вы могли передать тип функции (void(int, float) в вашем примере) в качестве параметра шаблона, а затем специализацию шаблона

template <typename Ret, typename... Args>
struct func_wrapper<Ret(Args...)>
 {
   // ...
 };

может разрешить возвращаемый тип и типы аргументов из типа функции.

...