简体   繁体   中英

Passing a functor or a function as an argument

I'm kinda new to C++ and I am currently playing around with templates to get a better understanding of them. Here's what I've been trying out:

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

I want to do pretty much the same thing but for a function this time. Basically something like:

myCont.sort<function>();

Just to be sure - I do not want this:

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

/Edit: I realize I may not have been exactly clear. I want to be able to call myCont.sort<function> is this possible? I realize that a function is not what's you'd call a class however it is possible to pass a generic function to 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;
}

I can even customize its return type:

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

But that is not the problem. I know I am not explaining it the best way I can, so if you want me to add something please tell me what. My idea is that I want to be able to do something like: myCont.sort(); or myCont.sort(function);

The gist of the question: Is there a way to pass a function template as an argument to a template of another function - just like I passed a class template as an argument to a template of another function:

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

If I got a function template called compare is there a way to do any of the following:

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

I want to pass a function template - not a specialization of compare - I can do this with a functor, so I wonder if I could do it with a function. I do not want to have:

myCont.sort(compare<some_type>);

I want to take a function template and then get a specialization for it inside of sort().

Thanks in advance!

PS: Seems the comments can be only small size so here's another question: Do you think that this( myCont.sort(compare) ) would have been possible(if there were default value for function template parameters in C++) with this code?

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

PS

Btw everything started with me wondering why I can't compile this(obviously because of the missing someFunc, but it's logical that list.sort should be able to deduce the type of someFunc from the type for which the list is specialized):

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

};

C++ doesn't have any type that represents a group of overloaded functions or function template. The only way to pass a group of functions is as a class containing them.

If you want to pass a single function (possibly a template function instance), you can use a function pointer (or maybe even a reference) as a template argument. But the type of the function cannot be deduced, it will have to exactly match the formal type of the template argument. And there's very little value to passing it as a template argument instead of a normal parameter -- if the parameter is constant, then during inlining a good compiler will optimize the function pointer to a direct call and even inline that as well.


Response to edit:

myCont.sort(compare) does work. You just made a small mistake in the code, by making a template argument Ty and never using it. An unused argument can't be deduced. Look at


By the way, instead of this

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

};

you might like

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

};

and the new C++14 lambdas that generate a templated operator() automagically.

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