【问题标题】:generic lookup method?通用查找方法?
【发布时间】:2009-07-16 12:29:59
【问题描述】:

我想要一个从向量中检索数据的通用方法。

我有以下类和向量:

class myClass
{
    public:

    myClass(int myX, float myZ, std::string myFoo)
        : x ( myX )
        , z ( myZ )
        , foo ( myFoo )
    {

    }
    myClass()
    {

    }

    int x;
    float z;
    std::string foo;

} ;
std::vector < myClass > myVector;

(完整代码可以看这里:http://codepad.org/iDD1Wme5

在此示例中,我希望能够根据“z”或“foo”成员检索向量中的对象,而无需编写另外 2 个类似于“FindDataById”的函数。

这可能吗?

【问题讨论】:

  • 插入了一些代码,以便人们阅读问题。

标签: c++ templates vector


【解决方案1】:

您可以使用模板和指向成员的指针。

typedef vector<myClass> myVector;

template<typename T>
bool FindDataById(const T &id, T myClass::* idMember, myClass &theClass,
                                                       const myVector &theVector)
{
   for(myVector::const_iterator itr = theVector.begin(); itr != myVector.end();
                                                                          ++itr){
       if((*itr).*idMember == id){
          theClass = *itr;
          return true;
   }

   return false;
}

然后调用使用,例如,

FindDataById(string("name"), &myClass::foo, theClass, theVector)
FindDataById(5, &myClass::x, theClass, theVector)
FindDataById(5.25f, &myClass::z, theClass, theVector)

或者,采用find_if 的想法:

template<typename T>
struct Finder {
   T val_;
   T myClass::* idMember_;

   Finder(T val, T myClass::* idMember) : val_(val), idMember_(idMember) {}
   bool operator()(const myClass &obj) { return obj.*idMember_ == val_; }
};

并使用:

find_if(theVector.begin(), theVector.end(), Finder<string>("name", &myClass::foo))
find_if(theVector.begin(), theVector.end(), Finder<int>(5, &myClass::x))
find_if(theVector.begin(), theVector.end(), Finder<float>(3.25f, &myClass::z))

查看 MSalters 的答案,了解自动推断模板参数的方法。

【讨论】:

  • “Finder”位不起作用,缺少模板参数。查看我的代码如何进行模板参数推导。
  • 对。编辑以提供另一种(可能不太优雅)的方式。
  • 你现在不需要字符串("name")了。
  • 再次正确。为此进行了编辑。谢谢。
【解决方案2】:

std::find_if已经被推荐了,但是没有代码示例,所以这里有一个更详细的版本:

定义两个函子来识别您感兴趣的对象:

struct z_equals {
  z_equals(float z) : z(z) {}

  bool operator()(const myClass& obj)
    return z == obj.z;
  }

  float z;
};


struct foo_equals {
  foo_equals(const std::string& foo) : foo(foo) {}

  bool operator()(const myClass& obj)
    return foo == obj.foo;
  }

  const std::string& foo;
};

现在,要搜索 z == 42.0f 或 foo == "hello world" 的元素:

std::find_if(myVector.begin(), myVector.end(), z_equals(42.0f));
std::find_if(myVector.begin(), myVector.end(), foo_equals("hello world"));

【讨论】:

    【解决方案3】:

    您可以使用仿函数并将其传递给您的查找方法。我的意思是,定义将重载bool operator( vectorElement element) 的类,在此运算符中,您将选择如何查找值的方法。

    template <typename T>
    class ILookUp
    {
        bool operator( vector<T> elem)
        {
          if (elem == something)
              return true;
          false;
        }
    };
    
    class VectorStorage
    {
         std::vector<Elements> lookup( ILookUp<Elements> lookup)
         {
    
             .....         
    
             if ( lookup(elem))
             {
                  //add element to vector or whatever.
             }
    
              .....
    
             return result;
         }
    
              .....
    
    }
    

    【讨论】:

      【解决方案4】:

      可能值得一看 std::find 在 algorithm 和 boost::lambda 中定义

      【讨论】:

        【解决方案5】:

        如果没有 lambda,您需要编写一些谓词,或者至少实例化它们:

        模板 struct member_select : public std::unary_function { 吨; TU::* m_u; member_select(T const& t, T U::* m_u) : t(t), m_u(m_u) {} bool operator()(U const& u) const { return u.*m_u == t; } }; 模板 member_select make_member_select(T const& t, T U::* m_u) { 返回成员选择(t,m_u); }

        使用:std::find_if(..., make_member_select("x", &amp;myClass::foo));

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-03-17
          • 1970-01-01
          • 1970-01-01
          • 2023-04-05
          • 2014-08-25
          • 1970-01-01
          • 2012-01-22
          • 1970-01-01
          相关资源
          最近更新 更多