1

I am writing a stl-like container class which has the following functions:

    Iterator begin(){
        return Iterator(data_.begin(), 1);
    }

    ConstIterator begin() const{
        return ConstIterator(data_.begin(), 1);
    }

I think I could make one function to replace both:

    template <typename itr0, typename itr1>
    itr0 begin(){
        return itr1(data_.begin(), 1);
    }

and when I call the following, the code is generated in compile time:

    Iterator it = foo.begin<Iterator, Iterator>();
    ConstIterator it = foo.begin<ConstIterator const?, ConstIterator>();

My first question is, what typename is actually ConstIterator begin() const?

Secondly, is there a way to make it so that this metaprogramming is transparent from outside of the class? i.e. I could still use the following code to call begin() as if it was written in a standard way?

    C foo;
    const C foo2;
    Iterator it = foo.begin();
    ConstIterator it = foo2.begin();
guinny
  • 1,522
  • 10
  • 19
  • Why are you using 2 template parameters on your begin method? – mfontanini Apr 25 '12 at 01:26
  • @fontanini hmm because I am not sure what typename ConstIterator begin() const has, so whether itr0 and itr1 are the same for the const case. – guinny Apr 25 '12 at 01:40

1 Answers1

1

Unfortunately you'll need to define the two methods separately since, as you've noted, their signature differs by the const modifier. There's no template wizardry available that can overcome that (at least none that I'm aware of).

You can however use a number of different techniques to combine their implementations into a single method. Here's one such option that avoids the need for any const_cast'ing:

struct Container
{
    template< typename I, typename C >
    friend I begin_impl( C & c ){
      return I( c.data_.begin(), 1 );
    }

    Iterator begin(){
        return begin_impl< Iterator >( *this ); // *this is "Container"
    }

    ConstIterator begin() const{
        return begin_impl< ConstIterator >( *this ); // *this is "Container const"
    }
};

See here for more options.

Community
  • 1
  • 1
Andrew Durward
  • 3,771
  • 1
  • 19
  • 30
  • `typename C` looks strange to me, why not just use `Container`? – user2k5 Apr 25 '12 at 02:40
  • @user2k5 Sorry, I could have made that more clear. When called from `begin()`, `C` will be `Container`. But when called from `begin() const`, `C` will be `Container const`. – Andrew Durward Apr 25 '12 at 12:56
  • @AndrewDurward thanks for the answer. This is one of the moment if there exists a solution, it's easy to find it. But if there exists none, I need to find people confirming it :) – guinny Apr 25 '12 at 14:27
  • @Andrew Nice use of template in this case and good explanation. And you don't really need to say sorry... :) – user2k5 Apr 25 '12 at 14:39
  • @AndrewDurward I am a little bit failing with my c++ skills... If I put your code directly into my project, begin_impl cannot be seen from the latter 2 functions... error is "undeclared begin_impl" – guinny Apr 26 '12 at 01:27
  • @YCHAI Strange, it works both on [ideone](http://ideone.com/T3SAo) (which uses gcc 4.3.4) as well as MSVC2008. – Andrew Durward Apr 26 '12 at 12:08
  • @AndrewDurward well, my Container is a class instead of a struct, maybe that's the difference? And I don't want to move begin_impl to the outside of the function, also the compiler prevents me to declare it as static... – guinny Apr 26 '12 at 16:15
  • @YCHAI My only suggestion is to start a new question with a complete description of the problem. – Andrew Durward Apr 26 '12 at 17:05