Reputation: 2224
I've some trouble to make use of template template parameters. Here is a very simplified example:
template <typename T>
struct Foo {
T t;
};
template <template <class X> class T>
struct Bar {
T<X> data;
X x;
};
int main()
{
Bar<Foo<int>> a;
}
The compiler (g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2) reports the following error:
main.cpp:8:5: error: ‘X’ was not declared in this scope
T<X> data;
^
main.cpp:8:6: error: template argument 1 is invalid
T<X> data;
^
Any idea what's wrong?
Upvotes: 14
Views: 8192
Reputation:
In
template <template <class X> class T>
The template type parameter X
is not a template parameter to the outermost template: it is a template parameter to the innermost template. It's rather similar to
int foo(int (*bar)(int x))
{
int y = x; // compiler error
}
which doesn't work since the function takes a single argument, bar
: there is no argument x
.
Depending upon what you are truly trying to do, you could add the second template parameter, with something like
template <typename X, template <typename> class T >
struct Bar
{
// ...
};
you can keep the declaration with a single type parameter, but pattern match to give a partial specialization that would define the class in the example context
template <typename T>
struct Bar;
template <typename X, template <typename> class T >
struct Bar<T<X>>
{
// ...
};
you could modify Foo
to have a useful nested type, and grab it that way
template <typename T>
struct Bar
{
using X = T::value_type;
};
or you could define a metafunction that extracts a template parameter from a template type, and get it that way:
template <typename T>
struct Bar
{
using X = get_parameter<T>;
};
The most flexible is the last version, except rather than a metafunction that extracts template arguments, you would declare a get_bar_parameter
function, and define a partial specialization that extracts the template parameter from a Foo<X>
(or a T<X>
). That way, if you ever decide in the future to use Bar
with classes where the right value of X
isn't computed that way, you can do so by giving an appropriate specialization for get_bar_parameter
.
Upvotes: 7
Reputation:
// method 1
template <typename T>
struct Foo {
typedef T Type;
T t;
};
template <typename T>
struct Bar {
T data;
typename T::Type x;
};
// method 2
template <typename T>
struct Hack
{
T t;
};
template <typename T>
struct TypeOf
{
typedef struct UnknownType Type;
};
template<>
struct TypeOf< Hack<int> >
{
typedef int Type;
};
template <typename T>
struct Baz {
T data;
typename TypeOf<T>::Type X;
};
int main()
{
Bar< Foo<int> > a;
Baz< Hack<int> > b;
return 0;
}
In method 1 information is provided with nested type. This requires changing original class.
In method 2 this information is provided with specialization of another template.
Upvotes: 0
Reputation: 48467
So I would like so make use of something like
Bar<Foo<>>
template <typename T = int>
struct Foo {
T t;
};
template <typename T>
struct Baz {
T t;
};
template <typename T>
struct Bar;
template <template <typename> class T, typename X>
struct Bar<T<X>> {
T<X> data;
X x;
};
int main()
{
Bar<Foo<>> a;
Bar<Baz<float>> b;
}
Upvotes: 14
Reputation: 3765
template <typename T>
struct Foo {
T t;
};
template <template <class> class T, class X>
struct Bar {
T<X> data;
X x;
};
int main()
{
Bar<Foo, int> a;
}
Upvotes: 9