创建需要指向方法函数的指针的模板谓词类,并随之而来的编译器错误

发布于 2024-09-11 16:11:57 字数 2090 浏览 11 评论 0原文

我正在构建一系列重复大量代码的谓词,因此被更改为基于 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 容器执行搜索并检查 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 中是否有我错过的东西可以在单个类中完成相同的工作?我总是可以将谓词分解为几个更具体的谓词,但我试图避免这种情况。

其次,你能帮我解决编译器错误吗?

I'm building a series of predicates that duplicate lots of code, and so are being changed into a single template function class based on the std::unary_function. The idea is that my class interface requires methods such as Element_t Element() and std::string Name() to be defined, so the predicate template arguments are the object type and a value type to which comparison will be made as follows:

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

Thus, if I have:

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

I would like to perform a search on a container of Atoms and check for either the Name or Element equality using my template predicate like so:

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

but compiling this returns the following error on the std::find_if line:

error: address of overloaded function with no contextual type information

Also, trying to form the same predicate for a check of the Element() as such:

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

creates a different error!

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>&)

Firstly, am I reinventing the wheel with this predicate? Is there something in the STL that I've missed that does the same job in a single class? I can always break the predicate down into several more specific ones, but I'm trying to avoid that.

Secondly, can you help me with the compiler errors?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小瓶盖 2024-09-18 16:11:57

我不知道有什么简单的方法可以使用 STL 提供的位来完成此操作。可能有一些聪明的 boost 方法,使用迭代器适配器或 boost::lambda,但我个人不会这样做。

显然,C++0x lambda 将使这一切变得简单。

您的问题是尝试将这样的函数转换

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

I don't know of any easy way to do this using the bits provided with the STL. There is probably some clever boost way, using iterator adapters, or boost::lambda, but personally I wouldn't go that way.

Obviously C++0x lambdas will make all this easy.

Your problem is attempting to cast a function like this:

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

into a function like this:

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

If you replace your typedef R (U::*fn_t)(); with typedef const R& (U::*fn_t)() const; then it should work.

The following avoids this problem and also provides type inference so that you can just write mem_fun_eq(&Atom::Name, atomname). It compiles for me, although I haven't tested it.

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);
}
非要怀念 2024-09-18 16:11:57

您是否想过尝试混合使用 mem_fun_refmem_fun 对象来代替成员函数调用?

基本上,您调用 mem_fun 来创建一个对象,该对象接受两个参数 T* 和函数 A 的模板参数(如果它有一个(或无效,如果没有)。因此,您可以像这样组合它:

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

编辑:

好吧,这并不完全有效,所以为什么不这样做:

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" ) );

Have you thought of trying to mix in a mem_fun_ref or mem_fun object in place of the member function call?

Basically, you call on mem_fun to create an object that accepts two arguments T* and a template argument to the function A if it has one (or void if it doesn't). Hence you combine it like so:

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:

Ok, that's not completely working so why not have:

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

then use bind2nd

find_if( atoms.begin(), atoms.end(), bind2nd( NamePred, "yo" ) );
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文