'recursive' template problem

Discussion in 'C++' started by Alexander Stippler, Jul 16, 2004.

  1. Hi,

    I have a little problem to design some template classes in a realizable way.
    I have some Container classes and some Proxy classes (proxies for
    elements). Looks like this:

    // P is the Proxy class.
    template <typename T, typename P>
    class Container
    {
    P
    whatever() { return P(); }
    };

    template <typename T>
    class Proxy1 { ... };

    template <typename T>
    class Proxy2 { ... };

    For some reason every instance of class Proxy needs to know, which Container
    class it is used for. Some behavior of Proxy is dependend on the specific
    Container. So, when I call method whatever() I want to give the information
    that I'm inside Container<T, P> to P. But I cannot give the Proxy class the
    information via another template parameter, cause I would end up in an
    endless recursive definition, since Container is parameterized by the
    Proxy. Got my problem?

    Best regards,
    alex
    Alexander Stippler, Jul 16, 2004
    #1
    1. Advertising

  2. Alexander Stippler

    Marc Guest

    Alexander Stippler wrote:

    > For some reason every instance of class Proxy needs to know, which Container
    > class it is used for. Some behavior of Proxy is dependend on the specific
    > Container. So, when I call method whatever() I want to give the information
    > that I'm inside Container<T, P> to P. But I cannot give the Proxy class the
    > information via another template parameter, cause I would end up in an
    > endless recursive definition, since Container is parameterized by the
    > Proxy. Got my problem?


    What's wrong with:
    template <typename T, template <typename> class P>
    class Container
    {
    typedef Container<T,P> Self;
    P<Self>
    etc
    ?
    Just because you cannot write the type as a single expression does not
    mean it is not a valid type.
    Marc, Jul 16, 2004
    #2
    1. Advertising

  3. Marc wrote:

    > What's wrong with:
    > template <typename T, template <typename> class P>
    > class Container
    > {
    > typedef Container<T,P> Self;
    > P<Self>
    > etc
    > ?
    > Just because you cannot write the type as a single expression does not
    > mean it is not a valid type.


    Thanks. Looks simple and correct. But I guess a default value for P is not
    realizable this way, is it?

    regards,
    alex
    Alexander Stippler, Jul 16, 2004
    #3
  4. Alexander Stippler wrote:

    > Marc wrote:
    >
    >> What's wrong with:
    >> template <typename T, template <typename> class P>
    >> class Container
    >> {
    >> typedef Container<T,P> Self;
    >> P<Self>
    >> etc
    >> ?
    >> Just because you cannot write the type as a single expression does not
    >> mean it is not a valid type.

    >
    > Thanks. Looks simple and correct. But I guess a default value for P is not
    > realizable this way, is it?
    >
    > regards,
    > alex


    I get some doubts. How do I instantiate such a class?

    Container<double, Proxy<Container<double, ....
    Alexander Stippler, Jul 16, 2004
    #4
  5. Alexander Stippler wrote:
    > Alexander Stippler wrote:
    >
    >
    >>Marc wrote:
    >>
    >>
    >>>What's wrong with:
    >>>template <typename T, template <typename> class P>
    >>>class Container
    >>>{
    >>>typedef Container<T,P> Self;
    >>>P<Self>
    >>>etc
    >>>?
    >>>Just because you cannot write the type as a single expression does not
    >>>mean it is not a valid type.

    >>
    >>Thanks. Looks simple and correct. But I guess a default value for P is not
    >>realizable this way, is it?
    >>
    >>regards,
    >> alex

    >
    >
    > I get some doubts. How do I instantiate such a class?
    >
    > Container<double, Proxy<Container<double, ....


    You probably need some way to terminate the instantiation loop:

    Container<double, Proxy<Container<double, NullProxy<void> > > ...

    Take a look at TypeList template idiom. The latest CUJ also has
    a good article by V.Myrnyy that uses a similar pattern.

    Victor
    Victor Bazarov, Jul 16, 2004
    #5
  6. Alexander Stippler

    tom_usenet Guest

    On Fri, 16 Jul 2004 18:19:14 +0200, Alexander Stippler
    <-ulm.de> wrote:

    >Alexander Stippler wrote:
    >
    >> Marc wrote:
    >>
    >>> What's wrong with:
    >>> template <typename T, template <typename> class P>
    >>> class Container
    >>> {
    >>> typedef Container<T,P> Self;
    >>> P<Self>
    >>> etc
    >>> ?
    >>> Just because you cannot write the type as a single expression does not
    >>> mean it is not a valid type.

    >>
    >> Thanks. Looks simple and correct. But I guess a default value for P is not
    >> realizable this way, is it?
    >>
    >> regards,
    >> alex

    >
    >I get some doubts. How do I instantiate such a class?
    >
    >Container<double, Proxy<Container<double, ....


    Container<double, Proxy>

    Tom
    tom_usenet, Jul 16, 2004
    #6
  7. OK, I will try to formulate my problem more concrete. Perhaps this helps.
    Given:

    template <typename T>
    class Proxy { ... };

    template <typename T, typename P = DefaultProxy<T> >
    class OneContainerType
    {
    public:
    P
    operator()(int pos)
    {
    return P(int);
    }
    };

    template <typename T, typename P = AnotherDefaultProxy<T> >
    class AnotherContainerType
    {
    ...
    };

    Now I have to pass the information, which Container type called
    operator(), since the implementation calls a template function
    specialized for each different Container type. But how?
    I do not want to provide an additional parameter for the Proxy
    constructor (due to efficiency).
    Any suggestions?

    best regards,
    alex
    Alexander Stippler, Jul 17, 2004
    #7
  8. "Alexander Stippler" <-ulm.de> wrote...
    > OK, I will try to formulate my problem more concrete. Perhaps this helps.
    > Given:
    >
    > template <typename T>
    > class Proxy { ... };
    >
    > template <typename T, typename P = DefaultProxy<T> >
    > class OneContainerType
    > {
    > public:
    > P
    > operator()(int pos)
    > {
    > return P(int);
    > }
    > };
    >
    > template <typename T, typename P = AnotherDefaultProxy<T> >
    > class AnotherContainerType
    > {
    > ...


    Supposedly the same as in 'OneContainerType', right?

    > };
    >
    > Now I have to pass the information, which Container type called
    > operator(),


    You mean, which Container type initialised the P.

    > since the implementation calls a template function
    > specialized for each different Container type. But how?
    > I do not want to provide an additional parameter for the Proxy
    > constructor (due to efficiency).
    > Any suggestions?


    How about this: you create a templatised 'construct' member function
    in your proxy and use that instead of the constructor?

    template<class T> class DefaultProxy {
    ...

    DefaultProxy(T t); // normal constructor

    template<class C> DefaultProxy construct(T t) {
    DefaultProxy dp(t);
    // use the 'C' here as you want
    ...
    return dp;
    }
    };

    template <typename T, typename P = DefaultProxy<T> >
    class OneContainerType {
    P operator()(int pos) {
    return P::construct<OneContainerType>(pos);
    }
    };

    (you may need to put the keyword 'template' somewhere here, I am not
    sure)

    I know, it may not be the solution you seek, but given the information
    you provided, I could only come up with this half-assed scheme...

    Good luck!

    Victor
    Victor Bazarov, Jul 18, 2004
    #8
  9. Victor Bazarov wrote:

    > How about this: you create a templatised 'construct' member function
    > in your proxy and use that instead of the constructor?
    >


    I will try this. Sounds very good (and too simple not to get it on my
    own :-(( ).
    Thanks a lot for your help. I was really frustrated already.

    Best regards,
    Alex
    Alexander Stippler, Jul 18, 2004
    #9
  10. Hi,

    I was exulting to early. My problem wasn't formulated good enough. So your
    proposal is adequate for the situation I described, but not for my problem.
    Some more details:

    Victor Bazarov wrote:

    >>
    >> Now I have to pass the information, which Container type called
    >> operator(),

    >
    > You mean, which Container type initialised the P.


    Not exactly. Initializing is not enough. The P object has to know
    by which Container it was created for all its lifetime. Several member
    functions need this information. Thus a templatized constructor is not
    enough.

    > I know, it may not be the solution you seek, but given the information
    > you provided, I could only come up with this half-assed scheme...
    >


    I was really unprecise. Sorry.

    Hope you can help me again. This little thing is quite essential for my
    application,

    Best regards,
    alex
    Alexander Stippler, Jul 19, 2004
    #10
  11. Alexander Stippler

    tom_usenet Guest

    On Mon, 19 Jul 2004 10:47:23 +0200, Alexander Stippler
    <-ulm.de> wrote:

    >Hi,
    >
    >I was exulting to early. My problem wasn't formulated good enough. So your
    >proposal is adequate for the situation I described, but not for my problem.
    >Some more details:
    >
    >Victor Bazarov wrote:
    >
    >>>
    >>> Now I have to pass the information, which Container type called
    >>> operator(),

    >>
    >> You mean, which Container type initialised the P.

    >
    >Not exactly. Initializing is not enough. The P object has to know
    >by which Container it was created for all its lifetime. Several member
    >functions need this information. Thus a templatized constructor is not
    >enough.
    >
    >> I know, it may not be the solution you seek, but given the information
    >> you provided, I could only come up with this half-assed scheme...
    >>

    >
    >I was really unprecise. Sorry.
    >
    >Hope you can help me again. This little thing is quite essential for my
    >application,


    How about:

    template <typename T, typename Container>
    class Proxy
    {
    public:
    Proxy(int pos){}
    };

    template <typename T, template <class T, class Container> class P>
    class OneContainerType
    {
    public:
    typedef P<T, OneContainerType> proxy_type;
    proxy_type operator()(int pos)
    {
    return proxy_type(pos);
    }
    };

    int main()
    {
    typedef OneContainerType<int, Proxy> container_type;
    container_type container;
    container_type::proxy_type proxy = container(10);
    }

    That uses a template template paramenter for the proxy.

    Tom
    tom_usenet, Jul 19, 2004
    #11
  12. tom_usenet wrote:

    > template <typename T, typename Container>
    > class Proxy
    > {
    > public:
    > Proxy(int pos){}
    > };
    >
    > template <typename T, template <class T, class Container> class P>
    > class OneContainerType
    > {
    > public:
    > typedef P<T, OneContainerType> proxy_type;
    > proxy_type operator()(int pos)
    > {
    > return proxy_type(pos);
    > }
    > };
    >
    > int main()
    > {
    > typedef OneContainerType<int, Proxy> container_type;
    > container_type container;
    > container_type::proxy_type proxy = container(10);
    > }


    Interesting approach. If I am honest, I do not understand, why it works, but
    the compiler says its fine (as soon as I remove the names from the template
    template parameters).
    Could you please give me an idea how the typedef works. You just say Proxy,
    but how does the compiler know how to instatiate the template parameters of
    the Proxy type? Now I know again I know nothing about templates :-<.

    Best regards,
    alex
    Alexander Stippler, Jul 19, 2004
    #12
  13. Alexander Stippler

    tom_usenet Guest

    On Mon, 19 Jul 2004 20:17:56 +0200, Alexander Stippler
    <-ulm.de> wrote:

    >tom_usenet wrote:
    >
    >> template <typename T, typename Container>
    >> class Proxy
    >> {
    >> public:
    >> Proxy(int pos){}
    >> };
    >>
    >> template <typename T, template <class T, class Container> class P>
    >> class OneContainerType
    >> {
    >> public:
    >> typedef P<T, OneContainerType> proxy_type;
    >> proxy_type operator()(int pos)
    >> {
    >> return proxy_type(pos);
    >> }
    >> };
    >>
    >> int main()
    >> {
    >> typedef OneContainerType<int, Proxy> container_type;
    >> container_type container;
    >> container_type::proxy_type proxy = container(10);
    >> }

    >
    >Interesting approach. If I am honest, I do not understand, why it works, but
    >the compiler says its fine (as soon as I remove the names from the template
    >template parameters).


    Whoops, the reuse of "T" is the error, but there is no need for the
    names, except perhaps for code clarity (as with parameter names in
    function prototypes).

    >Could you please give me an idea how the typedef works. You just say Proxy,
    >but how does the compiler know how to instatiate the template parameters of
    >the Proxy type? Now I know again I know nothing about templates :-<.


    You can have a template parameter that takes a template.

    template <typename T, template <class, class> class P>

    That defines the P parameter as taking a template with two type
    parameters. Proxy is such a template, so it can be passed in as the P
    parameter. Then, inside the definition of OneContainerType, you can
    use P as a template with two template type parameters, just like
    Proxy:
    typedef P<T, OneContainerType> proxy_type;

    Then you can instantiate your container types with different proxy
    templates, and then use the proxy_type typedef to access the proxy
    type that is associated with that container.

    Tom
    tom_usenet, Jul 20, 2004
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris Theis
    Replies:
    2
    Views:
    454
    Chris Theis
    Jul 24, 2003
  2. tom_usenet
    Replies:
    0
    Views:
    524
    tom_usenet
    Jul 24, 2003
  3. IR
    Replies:
    3
    Views:
    409
  4. n00m
    Replies:
    12
    Views:
    1,102
  5. vamsi
    Replies:
    21
    Views:
    2,049
    Keith Thompson
    Mar 9, 2009
Loading...

Share This Page