简体   繁体   中英

How to use std::function with a template argument

Why does this not work (in C++11) and how can I fix it:

#include <iostream>
#include <functional>

using namespace std;

template <typename T>
int apply(string x, const function<int(T)>& fn)
{
    T t = { x };
    return fn(t);
}

struct S {
    string data;
};

int process_s(const S& s)
{
    return s.data.size();
}

int main()
{
    cout << apply("abc", process_s);
}

The error is

prog.cc:21:8: error: no matching function for call to 'apply'
        cout<<apply("abc", process_s);
              ^~~~~
prog.cc:7:5: note: candidate template ignored: 
  could not match 'function<int (type-parameter-0-0)>'
  against 'int (const S &)'
int apply(string x, const function<int(T)>& fn) {
    ^
1 error generated.

I tried the approach from here , but it doesn't work either:

#include <iostream>
#include <functional>

using namespace std;

template <typename T>
struct id {
    typedef T type;
};

template <typename T>
using nondeduced = typename id<T>::type;

template <typename T>
int apply(string x, const function<nondeduced<int(T)> >& fn)
{
    T t = { x };
    return fn(t);
}

struct S {
    string data;
};

int process_s(const S& s)
{
    return s.data.size();
}

int main()
{
    cout << apply("abc", process_s);
}

The second approach only works when there's another way to deduce T . Your use case has no other function parameter which can be used for that deduction.

The deduction fails in your original attempt because a function pointer/reference ( process_s ) is not a std::function . Implicit conversion won't count, it has to be an object whose type is a std::function instantiation for the deduction to succeed.

Assuming there's no option to add any more parameters to the function, you are left with two options:

  1. Specify the template argument explicitly, as in apply<S>(...) .
  2. Create a std::function object and pass it to your first attempt, as the second function argument.

The second choice can be less ugly in C++17 since there are now deduction guides available. So the invocation can in fact become apply("abc", std::function{process_s});

As @StoryTeller states, an implicit conversion does not count.

The other option that can be considered is, giving up on using std::function . Then it will put you in the right place to start compiling at:

template <typename T>
int apply(string x, int(&fn)(T))
{
    T t = { x };
    return fn(t);
}

Not to mention that you can avoid the overhead of std::function as well.

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