Создание класса предиката шаблона, требующего указатель на функцию метода и последующие ошибки компилятора - PullRequest
2 голосов
/ 27 июля 2010

Я строю серию предикатов, которые дублируют много кода, и поэтому меняются в единый класс функций шаблона на основе std::unary_function. Идея состоит в том, что мой интерфейс класса требует определения таких методов, как Element_t Element() и std::string Name(), поэтому аргументы шаблона предиката - это тип объекта и тип значения, с которым будет производиться сравнение следующим образом:

// generic predicate for comparing an attribute of object pointers to a specified test value
template <class U, typename R>
class mem_fun_eq : public std::unary_function <U*, bool> {
  private:
    typedef R (U::*fn_t)();
    fn_t fn; 
    R val;
  public:
    explicit mem_fun_eq (fn_t f, R& r) : fn(f), val(r) { } 
    bool operator() (U * u) const {
      return (u->*fn)() == val;
    }   
}; 

Таким образом, если у меня есть:

class Atom {
  public:
    const Element_t& Element() const { return _element; }
    const std::string& Name() const { return _name; }
};

Я хотел бы выполнить поиск в контейнере Atom s и проверить равенство Name или Element, используя мой шаблонный предикат, например:

typedef std::string (Atom::*fn)() const;

Atom_it it = std::find_if( _atoms.begin(), _atoms.end(), mem_fun_eq <Atom, std::string> ((fn)&Atom::Name, atomname));

, но его компиляция возвращает следующую ошибку в строке std::find_if:

error: address of overloaded function with no contextual type information

Также, пытаясь сформировать тот же предикат для проверки Element() как таковой:

typedef Atom::Element_t& (Atom::*fn)() const;

Atom_it it = std::find_if(_atoms.begin(), _atoms.end(), mem_fun_eq <Atom, Atom::Element_t> ((fn)&Atom::Element, elmt);

создает другую ошибку!

error: no matching function for call to ‘mem_fun_eq<Atom, Atom::Element_t>::mem_fun_eq(Atom::Element_t& (Atom::*)()const, const Atom::Element_t&)’
note: candidates are: mem_fun_eq<U, R>::mem_fun_eq(R (U::*)(), R&) [with U = Atom, R = Atom::Element_t]
note:                 mem_fun_eq<Atom, Atom::Element_t>::mem_fun_eq(const mem_fun_eq<Atom, Atom::Element_t>&)

Во-первых, я заново изобретаю колесо с этим предикатом? Есть ли что-то в STL, что я пропустил, что делает ту же работу в одном классе? Я всегда могу разбить предикат на несколько более конкретных, но я пытаюсь избежать этого.

Во-вторых, можете ли вы мне помочь с ошибками компилятора?

Ответы [ 2 ]

3 голосов
/ 27 июля 2010

Я не знаю ни одного простого способа сделать это, используя биты, поставляемые с STL. Возможно, есть какой-то умный способ повышения, использующий адаптеры итераторов или boost :: lambda, но лично я бы не пошел по этому пути.

Очевидно, что лямбды C ++ 0x облегчат все это.

Ваша проблема пытается создать такую ​​функцию:

const std::string&(Atom::*)()

в функцию, подобную этой:

std::string (Atom::*)()

Если вы замените typedef R (U::*fn_t)(); на typedef const R& (U::*fn_t)() const;, тогда он должен работать.

Следующее позволяет избежать этой проблемы, а также обеспечивает вывод типа, так что вы можете просто написать mem_fun_eq(&Atom::Name, atomname). Он компилируется для меня, хотя я его не проверял.

template<typename U, typename R, typename S>
class mem_fun_eq_t : public std::unary_function<U const*, bool>
{
private:
    R (U::*fn_)() const;
    S val_;
public:
    mem_fun_eq_t(R (U::*fn )() const, S val) : fn_(fn), val_(val){}
    bool operator()(U * u)
    {
        return (u->*fn_)() == val_;
    }
};

template<typename U, typename R, typename S>
mem_fun_eq_t<U, R, S> mem_fun_eq(R (U::*fn)() const, S val)
{
    return mem_fun_eq_t<U, R, S>(fn, val);
}
2 голосов
/ 27 июля 2010

Задумывались ли вы о попытке смешать объект mem_fun_ref или mem_fun вместо вызова функции-члена?

Обычно вы вызываете mem_fun, чтобы создать объект, который принимает два аргумента T* и аргумент шаблона для функции A, если он есть (или void, если его нет). Следовательно, вы комбинируете это так:

template<typename MemFunc, typename CompareType, typename T>
struct MyPredicate{
    MyPredicate(MemFunc _functionObj, CompareType _value) 
    : m_Value(_value),
    m_Function(_functionObj){}

    bool operator()(const T &_input){
         return m_Value == m_Function(_input);
    }

 private:
    MemFunc m_Function;
    CompareType m_Value;
 };

Edit:

Хорошо, это не совсем работает, так почему бы не иметь:

struct NamePred: binary_function<Atom*,string,bool>{
    bool operator()(Atom *_obj, string _val){
        return _obj->Name() == _val;
    };
};

затем используйте bind2nd

find_if( atoms.begin(), atoms.end(), bind2nd( NamePred, "yo" ) );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...