Can I write a C ++ functor that accepts both a raw pointer and a smart pointer?

Given the following:

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

I have a container Foo* and I use std::find_if and std::not1 to find out if there are any elements in the container where bar() returns something other than the given value. The code is as follows:

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

Fast forward to the future, and now I have another container, this time containing std::tr1::shared_ptr<Foo> . I would like to just reuse my functor in the overloaded version of isAllEqual() . But I can not. Foo* and shared_ptr<Foo> are different types. And I need to inherit from unary_function , so I can use not1 . It would be more elegant if I could write the same functor twice.

Questions:

  • Is there a way to write IsEqual so that it can use both raw and smart pointers?
  • Did I handcuff myself using std::not1 ? Should I just write IsNotEqual instead?

Limitations:

  • I cannot use anything from the boost library.
  • Our compiler is not cool enough to support C ++ 0x lambdas.
+8
c ++ functor smart-pointers adapter
source share
5 answers
 // --*-- 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; } } 
+2
source share

What about:

 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); } 
+8
source share

My snapshot would be something like this:

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

You will have another instance of operator() for anything that is not possible with -> , so raw pointers and smart pointers.

+2
source share

Perhaps you can do something complicated with implicit conversions:

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

But I would really just write IsNotEqual .

+1
source share

Ben's answer is the only thing you can do in C ++ 03. In C ++ 0x, although / or with boost :: bind, you do not need to inherit from unary_function. This allows the use of the templated () operator. You can usually get away with C ++ 03, but I think this is technically wrong.

0
source share

Source: https://habr.com/ru/post/650102/


All Articles