2013-06-03 4 views
1

Я новичок в 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; 
} 

/Edit: Я понимаю, что, возможно, не было точно ясно. Я хочу иметь возможность позвонить 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 <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>()() 

Если я получил шаблон функции называется сравнить есть способ сделать любое из следующих действий:

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

Я хочу передать шаблон функции - не конкретизацией сравнить - Я могу сделать это с помощью функтора, поэтому я задаюсь вопросом, могу ли я сделать это с помощью функции. Я не хочу иметь:

myCont.sort(compare<some_type>); 

Я хочу взять шаблон функции, а затем получить специализацию для него внутри рода().

Заранее благодарен!

P.S .: Кажется, комментарии могут быть только небольшого размера, так вот еще один вопрос: Как вы думаете, что это (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; 
} 

P.S.

Btw все началось со мной, интересно, почему я не могу скомпилировать это (очевидно, из-за отсутствия someFunc, но это логично, что список.сортировать должны быть в состоянии вывести тип 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; 

}; 
+3

Итак, в чем ваш вопрос? –

+0

К сожалению, 14.3.3/1: «A _template-argument_ для шаблона _template-parameter_ должен быть именем шаблона класса или шаблона псевдонима, выраженным как _id-expression_». Таким образом, шаблон функции не может быть аргументом шаблона, например шаблоном класса. – aschepler

ответ

5

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

}; 

и новые C++ 14 лямбды которые генерируют templated operator() автоматически.

+0

Большое спасибо за этот ответ! Я только что изучал шаблоны, поэтому я действительно хотел попробовать с ними разные вещи. Я не хочу передавать экземпляр функции шаблона - мне нужно передать шаблон функции. – lightxbulb

+0

@lightxbulb: Я так понимаю. Вот почему я объяснил в своем первом параграфе, что они только способ передать целое семейство функций (что является шаблоном функции) - это помещать их в класс и передавать класс. –

+0

@lightxbulb: см. Мое редактирование, отвечающее на ваше изменение вопроса. –

Смежные вопросы