2

I have a container class that operates on pixels in various formats. Some formats just store the pixels in memory, so the reference type of the container is Pixel&. Other formats store the pixels in packed bytes. There's nothing to return a reference to, so the reference type in that case is a proxy type. All of my proxy types have an embedded typedef called value_type, which is the type of the underlying pixel.

I'm running into a problem when I try to write functors that operate on pixels. For instance, I'd like to be able to write something like:

std::for_each( container.begin(), container.end(), Incrementer() );

I've been able to get this to work two different ways, but I don't like either of them, so I'm wondering if this can be improved.

The first method is:

struct Incrementer {

  template <typename Pixel>
  void operator()( Pixel& p ) {
    p = p + 1;
  } 

  template <typename Proxy>
  void operator()( Proxy p, typename Proxy::value_type* dummy=0 ) {
    p = p + 1;
  }
};

The basic idea is that I have two overloads, one for the case where the container returns references to pixels and one where it returns proxies. I need that dummy argument for the second overload so that the reference case is unambiguous. The problem with this is that every functor I use needs these two overloads (including the dummy argument), so I think the interface is rather ugly.

Perhaps I could write some template magic to sort out the argument type, but I keep running into the problem that the compiler will never infer a reference argument, so I need to provide an overload with a non-const reference. A proxy, on the other hand, is a temporary, so it cannot be passed by non-const reference. That leaves me stuck with two overloads.

Is there something I'm missing?

The fallback solution would be something like:

  template < typename PixelReference >
  struct Incrementer {

    void operator()( PixelReference p ) {
      p = p + 1;
    }
  };

  std::for_each( container.begin(), container.end(),      
                 Incrementer< pixel_traits<Pixel,Format>::reference >() );

(assuming I have a traits class for pixels). Now I have to specify the reference type when the functor is created, which is often cumbersome.

Is there any way I can improve on either of these alternatives? I'm writing this container as a library, so I'm trying to make writing and using functors as easy as possible.

Thanks.

user1806566
  • 1,078
  • 6
  • 18

2 Answers2

2

Using std::for_each() might be holding you back. What if you use std::transform() instead? It even supports the same in-place modification:

transform( container.begin(), container.end(), container.begin(), Incrementer() );

Then Incrementer::operator() need only be implemented for pass-by-value, because it will no longer explicitly modify pixels in-place. Of course you will then need to support assigning a proxy value to your iterators, but perhaps that's not so difficult.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • I can definitely do that. Assigning a proxy to an iterator works fine, so I think that works as a good technical solution. My only fear is that I'm writing the container as a library, and I would think that users would expect for_each to work without bending over backwards too far to accommodate proxies. Thanks. – user1806566 Jun 03 '13 at 16:38
0

I think there are a few ways to solve your problem.

1.in your example both operator()s are identical, so you are already using compile time polymorphism and your problem is multiple definition of operator()

Edit:

The code should look like this:

struct Incrementer {
  template <typename Pixel_or_Proxy>
  void operator()( Pixel_or_Proxy& p ) {
    p = p + 1;
  }
};

2.use boost enable_if & disable_if and check for value_type with help of boost.mpl BOOST_MPL_HAS_XXX_TRAIT_DEF

3.in case your proxy is a template you can create a better overload for it:

template<class T>
void operator()(T t) { 
  // normal operation
}

template<class T>
void operator()(Proxy<T> t) {
  // proxy operation
}

Edit:

To option 2: As the bodies of the methods are equal you simply need to write one template method. The typenames Pixel and Proxy are only names without any semantical meaning to the compiler, only to the user. The compiler simply instantiates the template method with the given type. If you have methods wich are different you need to choose one of them via overloading. This can be done with enable_if and friends or via an extra call with help of type traits.

Community
  • 1
  • 1
Jan Herrmann
  • 2,717
  • 17
  • 21
  • Yes, the method bodies identical. I just can't come up with a method declaration that works for both, so I wind up implementing it twice. Regarding #2, isn't my dummy argument the same thing as what enable_if would do? Since the function objects are going to have to be written by users, I'd rather not expose them to a boost library they may not be familiar with. For #3, it's not a template, but I could write a template wrapper to make that syntax work - that would make the dummy_arg/enable_if thing moot. Thanks. – user1806566 Jun 03 '13 at 16:40
  • The reason for the two overloads is that one (the non-proxy) must be a non-const reference, but the proxy cannot be a non-const reference because proxies are temps. – user1806566 Jun 05 '13 at 22:41