鉴于以下内容:
struct Foo
{
int bar() const;
};
struct IsEqual : public std::unary_function<Foo*, bool>
{
int val;
IsEqual(int v) : val(v) {}
bool operator()(const Foo* elem) const
{
return elem->bar() == val;
}
};
我有一个Foo*
的容器,我使用std::find_if
和std::not1
来查看容器中是否有任何元素,其中bar()
返回的内容与给定内容不同值。代码如下所示:
// Are all elements equal to '2'?
bool isAllEqual(const std::vector<Foo*> &vec)
{
return find_if(vec.begin(), vec.end(), std::not1(IsEqual(2))) == vec.end();
}
快进到未来我现在有一个不同的容器,这次包含std::tr1::shared_ptr<Foo>
。我很乐意在isAllEqual()
的重载版本中重复使用我的仿函数。但我不能。 Foo*
和shared_ptr<Foo>
是不同的类型。我需要继承unary_function
,因此我可以使用not1
。如果我能避免两次写同一个仿函数,它会更优雅。
问题:
IsEqual
所以它可以同时使用原始指针和智能指针?std::not1
手铐自己?我应该只写IsNotEqual
吗?限制:
答案 0 :(得分:8)
怎么样:
template<typename T>
struct IsEqual : public std::unary_function<const T&, bool>
{
int val;
IsEqual(int v) : val(v) {}
bool operator()(const T& elem) const
{
return elem->bar() == val;
}
};
template<typename T>
IsEqual<T> DeduceEqualityComparer(int v, T) { return IsEqual<T>(v); }
// Are all elements equal to '2'?
template<typename TContainer>
bool isAllEqual(const TContainer& coll)
{
using std::begin; // in C++0x, or else write this really simple function yourself
using std::end;
if (begin(coll) == end(coll)) return true;
return find_if(begin(coll), end(coll), std::not1(DeduceEqualityComparer(2, *begin(coll)))) == end(coll);
}
答案 1 :(得分:2)
我的镜头会是这样的:
template<typename PtrToFoo>
struct IsEqual : public std::unary_function<PtrToFoo, bool>
{
int val;
IsEqual(int v) : val(v) {}
bool operator()(PtrToFoo elem) const
{
return elem->bar() == val;
}
};
对于operator()
无法解释的所有内容,您将拥有不同的->
实例,所以原始指针和智能指针。
答案 2 :(得分:2)
// --*-- C++ --*--
#include <vector>
#include <algorithm>
#include <iostream>
// Template unary function example.
template <typename T>
struct IsEqual : public std::unary_function<T, bool>
{
int v;
IsEqual (int v) : v (v) {}
bool operator () (const T & elem) const
{
return elem ? elem->bar () == v : false;
}
};
// Generic algorithm implementation example...
template <typename T1, typename T2>
bool isAllEqual (const T1 & c, T2 v)
{
return find_if (
c.begin (), c.end (),
std::not1 (IsEqual <typename T1::value_type> (v))) == c.end ();
}
// Some arbitrary pointer wrapper implementation,
// provided just for an example, not to include any
// specific smart pointer implementation.
template <typename T>
class WrappedPtr
{
const T *v;
public:
typedef void (WrappedPtr<T>::*unspecified_boolean_type) () const;
WrappedPtr (const T *v) : v (v) {}
const T *operator -> () const { return v; }
operator unspecified_boolean_type () const
{
return v != NULL ?
&WrappedPtr<T>::unspecified_boolean_true : NULL;
}
private:
void unspecified_boolean_true () const {}
};
// Example of structure that could be used with our algorithm.
struct Foo
{
int v;
Foo (int v) : v (v) {}
int bar () const
{
return v;
}
};
// Usage examples...
int main ()
{
Foo f1 (2), f2 (2);
// Example of using raw pointers...
{
std::vector<Foo *> vec;
vec.push_back (NULL);
vec.push_back (&f1);
vec.push_back (&f2);
if (isAllEqual (vec, 2))
std::cout << "All equal to 2" << std::endl;
else
std::cout << "Not all equal to 2" << std::endl;
}
// Example of using smart pointers...
{
std::vector< WrappedPtr<Foo> > vec;
vec.push_back (NULL);
vec.push_back (&f1);
vec.push_back (&f2);
if (isAllEqual (vec, 2))
std::cout << "All equal to 2" << std::endl;
else
std::cout << "Not all equal to 2" << std::endl;
}
}
答案 3 :(得分:1)
你可以通过隐式转换做一些棘手的事情:
class IsEqualArg {
public:
// Implicit conversion constructors!
IsEqualArg(Foo* foo) : ptr(foo) {}
IsEqualArg(const std::tr1::shared_ptr<Foo>& foo) : ptr(&*foo) {}
private:
Foo* ptr;
friend struct IsEqual;
};
struct IsEqualArg : public std::unary_function<IsEqualArg, bool> {
bool operator()( const IsEqualArg& arg ) const;
//...
};
但我真的只想写一个IsNotEqual
。
答案 4 :(得分:0)
Ben的回答是你在c ++ 03中唯一可以做的事情。在C ++ 0x中,和/或使用boost :: bind,您不需要继承unary_function。这允许您使用templated()运算符。你通常可以在C ++ 03中使用相同的东西,但我认为这样做在技术上是不正确的。