【问题标题】:Passing a functor or a function as an argument将仿函数或函数作为参数传递
【发布时间】:2013-06-03 13:54:22
【问题描述】:

我对 C++ 有点陌生,我目前正在使用模板来更好地理解它们。这是我一直在尝试的:

#include <iostream>
#include <typeinfo>
using namespace std;

template <typename T>
class someContainer
{
private:
    T val1;
    T val2;
public:
    someContainer(const T& in1, const T& in2)
        :val1(in1), val2(in2) {}

    template <template <typename Ty> class Comp>
    void sort()
    {
        bool result = Comp<T>()(val1, val2);
        cout << result << endl;

        return;
    }
};

template <typename R>
class Compare
{
public:
    bool operator () (const R& a, const R& b)
    {
        return a>b;
    }

};


int main()
{
    someContainer<int> myCont(7,6);
    myCont.sort<Compare>();


    cin.ignore();
    return 0;
}

我想做几乎相同的事情,但这次是为了一个函数。基本上是这样的:

myCont.sort<function>();

只是为了确定 - 我不想要这个:

#include <iostream>
#include <typeinfo>
using namespace std;

template <typename T>
class someContainer
{
private:
    T val1;
    T val2;
public:
    someContainer(const T& in1, const T& in2)
        :val1(in1), val2(in2) {}

    template <class Func>
    void sort(Func func)
    {
        bool result = func(val1,val2);
        cout << result << endl;

        return;
    }
};

//Try for sort functor

template <typename R>
bool compare(const R& a, const R& b)
{
    return a>b;
}


int main()
{
    someContainer<int> myCont(7,6);
    myCont.sort(compare<int>);


    cin.ignore();
    return 0;
}

/编辑: 我意识到我可能不太清楚。 我希望能够拨打myCont.sort&lt;function&gt; 这可能吗? 我意识到函数不是你所说的类,但是可以将通用函数传递给 sort():

#include <iostream>
#include <typeinfo>
using namespace std;

template <typename T>
class someContainer
{
private:
    T val1;
    T val2;
public:
    someContainer(const T& in1, const T& in2)
        :val1(in1), val2(in2) {}

    template <typename Ty>
    void sort(bool (*_comp)(const Ty&, const Ty&))
    {
        cout << "Comp is of type: " << typeid(_comp).name() << endl;
        cout << _comp(val1, val2) << endl;
        return;
    }
};

template <typename R>
bool compare(const R& a, const R& b)
{
    return a>b;
}

int main()
{
    someContainer<int> myCont(7,6);
    myCont.sort(compare<int>); 


    cin.ignore();
    return 0;
}

我什至可以自定义它的返回类型:

#include <iostream>
#include <typeinfo>
using namespace std;

template <typename T>
class someContainer
{
private:
    T val1;
    T val2;
public:
    someContainer(const T& in1, const T& in2)
        :val1(in1), val2(in2) {}

    template <typename Ret, typename Ty>
    void sort(Ret (*_comp)(const Ty&, const Ty&))
    {
        cout << "Comp is of type: " << typeid(_comp).name() << endl;
        cout << _comp(val1, val2) << endl;
        return;
    }
};

template <typename Ret, typename R>
Ret compare(const R& a, const R& b)
{
    return a>b;
}

int main()
{
    someContainer<int> myCont(7,6);
    myCont.sort(compare<bool,int>); 


    cin.ignore();
    return 0;
}

但这不是问题。我知道我并没有尽我所能解释它,所以如果你想让我添加一些东西,请告诉我什么。 我的想法是我希望能够执行以下操作: myCont.sort(); 要么 myCont.sort(函数);

问题的要点: 有没有办法将函数模板作为参数传递给另一个函数的模板 - 就像我将类模板作为参数传递给另一个函数的模板一样:

myCont.sort<Compare>(); // Compare is a template - not a template specialization
//later in sort we got Comp<T>()()

如果我有一个名为 compare 的函数模板,是否有办法执行以下任一操作:

myCont.sort<compare>();
myCont.sort(compare);

我想传递一个函数模板——而不是比较的特化——我可以用函子来做到这一点,所以我想知道我是否可以用一个函数来做到这一点。 我不想拥有:

myCont.sort(compare<some_type>);

我想获取一个函数模板,然后在 sort() 中对其进行专门化。

提前致谢!

附: 似乎 cmets 只能很小,所以这是另一个问题: 你认为这个(myCont.sort(compare)) 用这段代码是可能的吗(如果 C++ 中的函数模板参数有默认值)?

#include <iostream>
#include <typeinfo>
using namespace std;

template <typename T>
class someContainer
{
private:
    T val1;
    T val2;
public:
    someContainer(const T& in1, const T& in2)
        :val1(in1), val2(in2) {}

    template <typename Ret = bool ,typename Ty = T>
    void sort(Ret (*_comp)(const T&, const T&))
    {
        cout << "Comp is of type: " << typeid(_comp).name() << endl;
        cout << _comp(val1, val2) << endl;
        return;
    }
};

template <typename Ret, typename R>
Ret compare(const R& a, const R& b)
{
    return a>b;
}

int main()
{
    someContainer<int> myCont(7,6);
    myCont.sort(compare); 

    cin.ignore();
    return 0;
}

附言

顺便说一句,一切都始于我想知道为什么我不能编译它(显然是因为缺少 someFunc,但 list.sort 应该能够从列表专门针对的类型推断 someFunc 的类型是合乎逻辑的) :

#include <iostream>
#include <list>
using namespace std;

template <typename T>
void display(const T& input)
{
    for(auto i = input.cbegin(); i!=input.cend(); ++i)
        cout << *i << ' ';
    cout << endl;
    return;
}

template <typename R>
bool someFunc(const R& in1, const R& in2)
{
    return in1>in2;
}

int main()
{
    list<int> myList;
    myList.push_back(5);
    myList.push_back(137);
    myList.push_back(-77);
    display(myList);

    myList.sort(someFunc); //change it to myList.sort(someFunc<int>) and it works
    //however I believe the compiler should be able to infer the type of someFunc from
    //the type of myList - I guess the STL just wasn't written for having template 
    //functions as a binary predicate
    display(myList);

    cin.ignore();
    return 0;

};

【问题讨论】:

  • 那么你的问题是什么?
  • 抱歉,14.3.3/1:“模板 template-parametertemplate-argument 应是类模板的名称或别名模板,表示为 id-expression。"所以函数模板不能像类模板那样是模板参数。

标签: c++ function templates functor


【解决方案1】:

C++ 没有代表一组重载函数或函数模板的任何类型。传递一组函数的唯一方法是作为包含它们的类。

如果您想传递单个函数(可能是模板函数实例),您可以使用函数指针(甚至可能是引用)作为模板参数。但是函数的类型无法推断,它必须与模板参数的形式类型完全匹配。并且将其作为模板参数而不是普通参数传递几乎没有什么价值——如果参数是常量,那么在内联期间,一个好的编译器会优化函数指针,指向直接调用,甚至内联。


编辑回复:

myCont.sort(compare) 确实工作。您只是在代码中犯了一个小错误,通过创建模板参数Ty 并且从未使用它。无法推断出未使用的参数。看看


顺便说一句,而不是这个

template <typename R>
class Compare
{
public:
    bool operator () (const R& a, const R& b)
    {
        return a>b;
    }

};

你可能会喜欢

class Compare
{
public:
    template <typename R>
    bool operator () (const R& a, const R& b)
    {
        return a>b;
    }

};

以及自动生成模板化operator() 的新 C++14 lambda。

【讨论】:

  • 非常感谢这个答案!我一直在学习模板,所以我真的很想用它们尝试不同的东西。我不想传递模板函数实例 - 我想传递函数的模板。
  • @lightxbulb:我明白这一点。这就是为什么我在第一段中解释说,它们传递整个函数系列(这就是函数模板是什么)的唯一方法是将它们放在一个类中并传递该类。
  • @lightxbulb:查看我的编辑以响应您对问题的更改。
  • 啊-那个错误-我在编写示例时忘记更改。但是我仍然不能用 VS2012 运行它,你猜你可以用 gcc ......我得到这个:error C4519: default template arguments are only allowed on a class template,所以我猜编译器的差异。事实上,这是我尝试做的第一件事——但它没有用,这对我来说似乎很奇怪,所以我尝试寻找解决方法(这就是我使用仿函数方法的方式)——我的意思是这就是我的问题的来源——我猜测几年后他们可能会在 VS2012 中实现它(目前你不能将默认参数传递给函数)
  • 糟糕:“目前你不能将默认参数传递给函数” - 意思是“目前你不能将默认参数传递给函数模板”。也感谢 Ideone 网站!
猜你喜欢
  • 1970-01-01
  • 2010-12-22
  • 1970-01-01
  • 2021-04-13
  • 2013-01-27
  • 1970-01-01
  • 2023-04-02
相关资源
最近更新 更多