views:

1252

answers:

4

Consider the following use of template template parameters...

#include <iostream>

template <typename X>
class A
{
    X _t;
public:
    A(X t)
        :_t(t)
    {
    }
    X GetValue()
    {
        return _t;
    }
};

template <typename T, template <typename T> class C >
class B
{
    C<T> _c;
public:
    B(T t)
        :_c(t)
    {
    }
    T GetValue()
    {
        return _c.GetValue();
    }
};

using namespace std;

int main()
{
    B<int, A> b(10);
    cout<<b.GetValue();
    return 0;
}

Is there a way by which the template parameter T can be removed? For example is there a way to make the following work?

//Does not compile
template <template <typename T> class C >
class B
{
    C _c;
public:
    B(T t)
        :_c(t)
    {
    }
    T GetValue()
    {
        return _c.GetValue();
    }
};

int main()
{
    B< A<int> > b(10);
    cout<<b.GetValue();
    return 0;
}
+1  A: 

What is wrong with:

template <typename C >
struct B
{
    C c;
};

int main()
{
    B< A<int> > b;
    return 0;
}
coryan
My bad, the problem was not fully specified. Now it is.
SDX2000
+3  A: 

This is not possible. Note that this is a common misunderstanding: A<int> is not a class template anymore! So it would not fit to a template-template parameter, but would have to be accepted using a type-parameter:

template<typename C>
struct B {
    C c;
};

B< A<int> > b;

Your way of using a separate parameter is alright.

If you want to accept A<int> but want to re-bind it to another parameter, you can use this pattern, also used by standard-allocators:

template<typename T>
struct A {
    template<typename U>
    struct rebind {
        typedef A<U> type;
    };
};

template<typename C>
struct B {
    typename C::template rebind<float>::type c;
};

B< A<int> > b;

Now, B< A<int> >::c is of type A<float>. The typename before C:: tells the compiler the ::type at the end is a type and not a static non-type member. The template after C:: tells the compiler the rebind<float> is a template instantiation, and not a comparision.

Johannes Schaub - litb
Ok cool! Nice answer but unfortunately there can only be one answer and I think @sunlight posted his solution earlier to you. I have upvoted your answer.
SDX2000
+5  A: 

I assume you're after X, as well as A, in your code.

The usual pattern is to have

template<typename C>
struct B
{
   C c;
};

and then, inside classes eligible for substitution:

template<typename X>
class A
{
   typedef X type_name;
   X t;
};

Then you can access the template parameter using C::type_name.

Sunlight
Thanks for the answer though I eventually discovered this myself. I was in the process of editing the question and posting my work around but apparently I had come to the right place to ask this question!
SDX2000
note that Sunlight's answer is better than mine, since he has understood what you want. No need to rebind like i showed you. That would only be required if you use A<int>, but occasionally have the need or A<float>. Or if the user's view is A<int>, but you use A<float> .
Johannes Schaub - litb
A: 

You can nest parameters. That is, the value of a parameter can itself be parameterized.

template <typename X>
struct A
{
  X t;
};

template <typename  C>
struct B
{
  C c;
};

int main()
{
  B< A<int> > b;
  return 0;
}

In this example, the declaration of b in main() creates a specialization of A using int as the parameter, then it creates a specialization of B using A<int> as the parameter. Thus, in the specialization of B, C is A<int>.

mxg
Your solution is correct according to the original question but I have added some details I missed the first time. Thanks.
SDX2000