Serge Roussak
Serge Roussak

Reputation: 1807

Deduction of the function

Let's say we have a class template like this:

template<typename F>
class A
{
public:
  template<typename... Args>
  A(F f, Args... args)
  { /* Do something... */ }
};

And now I want to use it in some way like this one:

A<int(int)> a(::close, 1);

Now the question: is there any way to omit the <int(int)> because a compiler can know this information for the ::close? There is no need to save the "design" of the template.

As for concrete task, I need to design a template of a class. Objects of this class could take a function and parameters for this function at construction time and call this function later.

Upvotes: 32

Views: 1672

Answers (3)

Holt
Holt

Reputation: 37606

No, you (currently) cannot. The standard way of doing this is by creating "make_like" function (such as make_pair, make_optional ...):

template<typename F, typename... Args>
A<std::decay_t<F>> make_A (F &&f, Args&&... args) {
    return {std::forward<F>(f), std::forward<Args>(args)...};
}

C++17 will introduce template argument deduction for class which will allow you to do exactly what you want (see also Barry's answer below).

Upvotes: 35

Barry
Barry

Reputation: 303057

Thanks to the adoption of template parameter deduction for constructors, in C++17, you'll be able to just write:

A a(::close, 1);

Before that, you'll just need to write a factory to do the deduction for you:

template <class F, class... Args>
A<std::decay_t<F>> make_a(F&& f, Args&&... args) {
    return {std::forward<F>(f), std::forward<Args>(args)...};
}

auto a = make_a(::close, 1);

This is a little verbose, but at least you don't need to worry about efficiency - there will be no copies made here thanks to RVO.

Upvotes: 16

Benjamin Lindley
Benjamin Lindley

Reputation: 103703

You cannot omit the arguments of a template class, unless they are defaulted. What you can do is have a maker function which deduces the argument and forwards this argument to the template class, returning an object of the appropriate instantiation.

template<typename F, typename... Args>
A<F> make_A(F f, Args&&... args) {
    return A<F>(f, std::forward<Args>(args)...);
}

Upvotes: 11

Related Questions