2

I have a class that creates an std::function. For simplicity, I'll say the std::function returns a boolean for this example. The std::function needs to take in a variadic tuple. Currently, I have

template<class... FuncArgs>
class Function
{
public:
    // Type that std::function returns
    using func_ret_ty = bool;

private:
    std::function<func_ret_ty(std::tuple<FuncArgs...>)> m_Function;
    std::tuple<FuncArgs...> m_Args;  // Stores m_Function's arguments

public:
    Function(
        std::function<func_ret_ty(std::tuple<FuncArgs...>)> function,
        FuncArgs... args)
        : m_Function(function)
        , m_Args(std::make_tuple(std::forward<FuncArgs>(args)...))
    {}
};

My question is simple: will this work?

More specifically, I'm concerned because there seems to be a circular dependency in declaring the type for function. Another thought for implementation I had was:

template<class FuncTy, class FuncArgs...>
class Function
{
public:
    using func_ret_ty = bool;

private:
    FuncTy m_Function;
    std::tuple<FuncArgs...> m_Args;

public:
    Function(
        FuncTy function,
        FuncArgs... args)
        : m_Args(std::make_tuple(std::forward<FuncArgs>(args)...))
    {
        static_assert(
            std::is_same_v<FuncTy, std::function<func_ret_ty(std::tuple<FuncArgs...>)>>,
            "FuncTy invalid type!"
        );

        m_Function = std::move(function);
    }
};

Is the second implementation better? Is there a better way to go about doing this?

Drake Johnson
  • 640
  • 3
  • 19
  • 1
    Your `static_assert` is too restrictive, [`std::is_assignable`](https://en.cppreference.com/w/cpp/types/is_assignable) seems more appropriate. – Jarod42 Feb 03 '20 at 16:34
  • I don't see you *circular dependency*. – Jarod42 Feb 03 '20 at 16:35
  • @Jarod42 The reason I believed there was a circular dependency is because I declare the types for `FuncArgs...` after using those types in the `std::function` parameter type. – Drake Johnson Feb 03 '20 at 18:20

1 Answers1

2

The first implementation looks better to me, because you don't have to repeat yourself by providing the function arguments twice. Because you set the return type to bool, I would recommend changing the name of the class to Predicate, which is a well known term to describe functions that return boolean values.

Note that std::function can take parameter packs as template parameters too, so you can also do this:

std::function<func_ret_ty(FuncArgs...)> m_Function;
Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
  • Thank you. The reason I didn't use the parameter pack directly is because I have a method in this class called `run()`, which passes `m_Args` into `m_Function`, meaning I need to store whatever the parameter pack's values. I don't know how to do that other than a tuple. Is there another way? – Drake Johnson Feb 03 '20 at 18:17
  • 1
    https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer does this answer your question? – Jan Schultke Feb 03 '20 at 18:41