如何将std :: function与模板参数一起使用

时间:2018-03-25 07:09:01

标签: c++ c++11 templates

为什么这不起作用(在C ++ 11中)以及如何解决它:

#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);
}

错误是

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.

我尝试了here的方法,但它也不起作用:

#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);
}

2 个答案:

答案 0 :(得分:4)

第二种方法只有在推导T的另一种方法时才有效。您的用例没有其他功能参数可用于该扣除。

由于函数指针/引用(process_s)不是std::function,因此推理在原始尝试中失败。隐式转换不会计算,它必须是一个对象,其类型为std::function实例,以便推断成功。

假设没有选项可以向函数添加更多参数,您可以选择两个选项:

  1. 明确指定模板参数,如apply<S>(...)
  2. 创建一个std::function对象,并将其作为第二个函数参数传递给第一次尝试。
  3. 第二种选择在C ++ 17中可能不那么难看,因为现在有deduction guides可用。因此,调用实际上可以变为apply("abc", std::function{process_s});

答案 1 :(得分:2)

正如@StoryTeller所述,隐式转换不计算在内。

可以考虑的另一个选择是放弃使用std::function。 然后它会把你带到正确的地方开始编译:

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

更不用说您也可以避免std::function的开销。