简体   繁体   中英

Function-style template syntax

I'm trying to write a rather simple class that takes a function, some arguments, and can execute the function with the arguments at a later time.

Currently, this is my code:

template<typename R, typename... Args>
class Delayed
{
public:
    using FunctionT = std::function<R(Args...)>;

    Delayed(FunctionT func, Args... args) : func(func), args(std::forward<Args>(args)...)
    {

    }

private:
    FunctionT func;
    std::tuple<Args...> args;
};

int main()
{
    std::function<double(double)> doubleMe = [](double x) { return x * 2.0; };

    //Works
    Delayed<double, double> delayed1(doubleMe, 2.0);

    //Doesn't work
    Delayed<double(double)> delayed2(doubleMe, 2.0);
}

The problem is that when I pass double(double) as an argument, instead of R being double and Args being double , it passes double(double) to R and nothing to Args .

According to cppreference , the template arguments for std::function is template< class R, class... Args > . So if I give it A(B,C) , it will pass A for the argument R and B,C for the variadic argument Args . But when I pass that to my class it passes A(B,C) for R and passes nothing for the variadic argument Args .

How is this function syntax supposed to be used and why does it work for std::function but not my class?

So if I give it A(B,C) , it will pass A for the argument R and B,C for the variadic argument Args .

Yes, but not for the reasons you think. If you look closely, you'll see that std::function partially specializes for any function type:

template<typename R, typename... Args>
class function<R(Args...)>;
//            ^^^^^^^^^^^^

You can imagine this as very primitive pattern matching. If you instantiate function with int(int, double) , then it makes sense that R is int , and Args is int, double . If a (partial) specialization is a better match than the catch-all generic primary template, then it is chosen, which is what happens here.

Remember: double(double) is a type, it's a function. There aren't any special rules involving it. So, in your case, you would do this:

template<typename R, typename... Args>
class Delayed<R(Args...)> : public Delayed<R, Args...> {
  //         ^^^^^^^^^^^^
  //       partially specialize to decompose function types

  // We need to inherit constructors (only).
  using Delayed<R, Args...>::Delayed;
};

Hope it clears up the confusion.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM