将函数作为参数传递给模板函数问题

时间:2019-06-28 21:33:07

标签: c++

我正在尝试创建一个具有5个参数的模板函数,其中四个应为迭代器,第五个应为函数。函数应该执行的操作本质上应该转换作为参数传递的第一和第二迭代器之间的块中的每个元素,并使用第五参数(函数)转换它们作​​为参数传递的第三和第四迭代器之间的复制。返回值是第一个块的所有元素的总和。

这是我想出的

#include <iostream>
#include <type_traits>
#include <vector>
#include <deque>
using namespace std;

int funk(int a) {
    return a*=2;
}

template <typename IterType1, typename IterType2>
auto MyFunction(IterType1 p1,
                IterType1 p2,
                IterType2 p3,
                IterType2 p4,
                decltype(p1[0]) CriteriaFunction(decltype(p1[0])))
-> decltype(p1[0])
{

    auto temp= remove_reference<decltype (p1[0])>::type;
    while(p1 != p2) {
        temp+=*p1;

        *p3++ = CriteriaFunction(*p1);
        p1++;

    }
    p4=++p3;

    return temp;
}

int main()
{
    vector<int> v1 = {1,2,3,4,5};
    deque<double> d1(5);

    auto it1 = v1.begin();
    auto it2 = v1.end();
    auto it3 = d1.begin();
    auto it4 = d1.end();

    cout << MyFunction(it1, it2, it3, it4, funk);
    return 0;

现在,我不确定我的模板函数是否可以按照我编写它的方式实际工作,但我稍后会对其进行更改。问题是它甚至无法编译,错误是:

main.cpp|48|error: invalid user-defined conversion from 'main()::<lambda(int)>' to 'int& (*)(int&)' [-fpermissive]|

现在,我熟悉将函数作为参数传递给其他函数,但是如果模板接收的函数取决于模板的类型名参数,该怎么办?我的语法错误吗?我该如何解决?

2 个答案:

答案 0 :(得分:1)

首先,您的意思是什么?

auto temp= remove_reference<decltype (p1[0])>::type;

您正在为变量分配类型。

接下来,decltype (p1[0])的实际类型是对存储在容器中的类型的引用。

正确的方法是使用std::iterator_traits而不是decltypeauto

typename std::iterator_traits<IterType1>::value_type

因此代码可能是:

auto MyFunction(
    IterType1 p1,
    IterType1 p2,
    IterType2 p3,
    IterType2 p4,
    typename std::iterator_traits<IterType1>::value_type 
        CriteriaFunction(typename std::iterator_traits<IterType1>::value_type))
           -> typename std::iterator_traits<IterType1>::value_type {

typename std::iterator_traits<IterType1>::value_type temp = typename std::iterator_traits<IterType1>::value_type();

这将允许您编译代码。无论如何,从我的问题中可以理解,如果要将值插入第二个容器,则需要提供一个插入器,而不仅仅是迭代器。代码p4=++p3;不会移动第二个容器的末尾。

答案 1 :(得分:1)

您的语法没有错,但是decltype(p1[0])int &,而不是int,因此您的函数类型错误。

MyFunction实际上想要一个int &(*)(int &),但是funk的类型为int (*)(int)(它需要并返回一个普通的int,而不是引用)。

您可以使用remove_reference,但是解决此问题的最简单方法是不必费心尝试描述确切的类型。这样做反正会不必要地限制您:它将阻止使用带有operator()的lambda和对象。

为什么不这样做:

template <typename IterType1, typename IterType2, typename FuncType>
auto MyFunction(IterType1 p1, IterType1 p2, IterType2 p3, IterType2 p4, FuncType CriteriaFunction) {
    ...
}

?让编译器担心FuncType的细节。

接下来的两个问题在这里:

auto temp= remove_reference<decltype (p1[0])>::type;

编译器假定remove_reference<decltype (p1[0])>::type引用值(而不是类型)(通常与从属名称相同)。这也是使初始化auto temp = ...编译所需要的。但是,如果尝试实例化此函数模板,则它将失败,因为::type是类型而不是值。

您可以使用typename告诉编译器::type实际上是一种类型:

auto temp = typename remove_reference<decltype (p1[0])>::type;

...但那是一个语法错误,就像auto i = int;一样。

但是,

auto temp = typename remove_reference<decltype (p1[0])>::type();

编译并工作。在这里,我们实例化类型为remove_reference<...>::type的默认值。