Mix of template and struct - c++

I have a template class defined as follow :
template <class T1, class T2>
class MyClass { };
In this class, I need a struct that contains one member of type T1. How can I do that ?
I tried the following, but it didn't work :
template <class T1, class T2>
class MyClass {
typedef struct {
T1 templateMember;
// rest of members
} myStruct;
// rest of class definition
};
EDIT: As requested, I use VS2008 and get the following error :
'MyClass<T1,T2>::myStruct' uses undefined class 'T1'

Just remove typedef:
template <class T1, class T2>
class MyClass {
struct myStruct{
T1 templateMember;
// rest of members
} ;
};

template <class T1>
struct myStruct{
T1 templateMember;
// rest of members
};
template <class T1, class T2>
class MyClass {
myStruct<T1> mystruct;
// rest of class definition
};

Are you sure this is exactly what you typed?
template <class T1, class T2>
class MyClass {
public:
typedef struct {
T1 templateMember;
// rest of members
} myStruct;
// rest of class definition
};
MyClass<int, float> c;
MyClass<int, float>::myStruct ms;
This compiles and works just fine for me in VS2008 SP1. Note that I added the public: so that I could access myStruct, but it does not affect the correctness of the rest of the declaration.

Related

Use nested class of templated class as template template parameter in C++

In C++, I'd like to use a nested class inside a templated class as template template parameter. For non-nested classes the pattern is:
template<class T>
class A {
public:
T a;
// ...
};
template<class T, template<class ST> class S>
class B {
public:
S<T> b;
// ...
};
B<int, A> b;
Now I'd like to add a nested class to A and use this nested class as template template parameter S of class B, like this:
template<class T>
class A {
public:
class AA {
public:
T aa;
// ...
};
// ...
};
template<class T, template<class ST> class S>
class B {
public:
S<T> b;
// ...
};
B<int, A> b1; // ok
B<int, A::AA> b2; // error
B<int, A<int>::AA> b3; // error
I understand that the declarations of b2 and b3 are errors because A::AA is incomplete and A<int>::AA is not a template.
I would like to be able to declare something similar to b2. The idea is that A and B should both use the same class T.
I would like to be able to declare a number of classes similar to A with individually named sub-classes. Another use of this I can think of are multiple sub-classes of A that can be used as template template parameter to B.
One workaround I see is to refrain from using individual names on the sub-classes of A, use the b1 declaration (use A as template template parameter S for B) and change the implementation of B accordingly (i.e. use S::AA<T> instead of S<T>):
template<class T, template<class ST> class S>
class B {
public:
S::AA<T> b;
// ...
};
B<int, A> b;
The other workaround I see is to reduce the template template parameter of class B to a simple template parameter, and ensure the same T by other means.
Is there some other possibility? If yes, how?
Edit: Added forgotten class in template for B and changed template template parameter name to ST.
This works for me:
template<class T>
class A {
public:
class AA {
public:
T aa;
// ...
};
// ...
};
template<class T, template<class ST> class S >
class B {
public:
S<T> b;
// ...
};
template<class T> using NestedAA = typename A<T>::AA;
int main()
{
B<int, NestedAA> b; // ok
return 0;
}
If for any reason you are constrained to C++03, type aliases won't be available to you. You can then replace the "using" statement with the following definition for NestedAA:
template<class T>
class NestedAA : public A<T>::AA
{
};
You may create an template alias:
template <typename T>
using innerAA = typename A<T>::AA;
and then
B<int, innerAA> b42;
Demo
Assuming you only want the nested case to work, and since AA itself is not a template you could just drop the template for B's 2nd parameter like so:
template<class T>
class A {
public:
class AA {
public:
T aa;
// ...
};
// ...
};
template<class T, class S>
class B {
public:
S b;
// ...
};
//B<int, A> b1; // error
B<int, A<int>::AA> b2; // ok
PS Your original declaration of B needs an extra 'class' to compile on g++ 5.4
template<class T, template<class T> class S>

Access nested template types

Let's say there is a class A and MyType
template<typename DataType>
class MyType {
...
}
template<typename MyType>
class A {
...
}
When I create an instance of A with A<MyType<int>> how can I access the template type int inside A?
Expose a type alias to the user:
template<typename DataType>
class MyType {
public:
using InnerDataType = DataType;
};
template<typename MyType>
class A {
public:
using InnerType = MyType;
};
Usage:
using MyA = A<MyType<int>>;
static_assert(std::is_same<
typename MyA::InnerType::InnerDataType,
int>{});
live example on wandbox
Another method would be like this:
template <typename DataType>
class MyType { ... };
template<typename X> // template parameter name changed for clarity
class A; // intentionally left undefined
template<typename Y>
class A<MyType<Y>> { ...Y... }; // a specialisation
... A<MyType<int>> ... // Y in the definition of A is int
This way one can only instantiate A with instances of MyType.
If there's a need to instantiate A with any templated type, one uses a bit different specialisation:
template<template<typename...> X, typename Y>
class A<X<Y>> { ...X<Y>... }; // a specialisation
... A<MyType<int>> ... // X in the definition of A is MyType, Y is int
... A<OtherType<double>> ... // X is OtherType, Y is double
This way, one can pass any templated type that doesn't have non-type template parameters.

typedef template without template rebind. Use as a template of template class parameter

I want to do something like this:
template<class T>
class BaseSubscriber {};
template<class T>
class BasePublisher
{
// not working : invalid use of template-name 'BaseSubscriber' without an argument list
typedef BaseSubscriber SubscriberType;
// compiling
typedef BaseSubscriber<T> SubscriberTypeT;
};
template< template<class T> class Subscriber, class Data >
class ClassA:
public Subscriber<Data>
{
};
template< template<class T> class Publisher, class Data >
class ClassB:
public Publisher<Data>
{
// Ok, but I want that the type "BaseSubscriber" depends on the template parameter Publisher
void method1(ClassA<BaseSubscriber, Data>&);
// I want something like that. But how to define SubscriberType ?
void method2(ClassA<Publisher<Data>::SubscriberType, Data>&);
// or (SubscriberType only depends on the Publisher, nor on the Data)
void method2(ClassA<Publisher::SubscriberType, Data>&);
// Error : template argument is invalid
void method3(ClassA<Publisher::SubscriberTypeT, Data>&);
};
Is it possible to define some SubscriberType that I can use for classA template parameter? Or is there any work around?
If possible I'd like to keep the classA prototype. I don't want to change it in
template<class TSubscriber > classA {};
And I can't use C++11.
Thanks a lot for your answers.
It is a bit confusing what you mean when you say:
// I want something like that. But how to define SubscriberType ?
void method2(ClassA<Publisher::SubscriberType>);
As Publisher is a template yet you're not passing it any arguments.
Anyway, here are some options:
In C++11 you can use template aliases:
template<class T>
class BasePublisher
{
template<typename U>
using SubscriberType = BaseSubscriber<U>;
};
You can also use nested classes:
template<class T>
class BaseSubscriber {};
template<class T>
class BasePublisher
{
template<class U>
class BaseSubscriber {};
};
Or change ClassA to use a type member:
template<class T>
class BasePublisher
{
template<class U>
struct SubscriberType {
typedef BaseSubscriber<U> type;
};
};
template< template<class T> class SubscriberT >
class ClassA {
typedef typename SubscriberT::type Subscriber;
};
Or sometimes inheritance works if you don't need an alias:
template<class T>
class BasePublisher
{
template<class U>
struct SubscriberType : BaseSubscriber<U> {};
};
Template aliases are not allowed in C++03 although they are in C++11.
Is your goal is to be able to do:
typename BaseSubscriber<A>::SubscriberType<B>
in C++03 you should use a nested class thus:
template< typename T > struct BasePublisher
{
template< typename U > struct Subscriber
{
typedef BaseSubcriber<U> type;
};
};
and now you can possibly do typename BasePublisher::Subscriber::type;
In C++11 the syntax would be:
template < typename T > struct BasePublisher
{
template< typename U > using SubscriberType = BaseSubscriber<U>;
};
there are not many compilers that support that yet.
although as you can't do typename typename it might need another typedef in between.
If I get it correctly you want ClassA to get an instantiation of BaseSubscriber, for example BaseSubscriber<my_tag> and ClassB on an instantiation of BasePublisher. is it correct?
If your answer is yes, then why you declare template argument of ClassA and ClassB as template, you don't want to do something with it in ClassA or ClassB, so it should be a class not a templated class:
template<class T>
class BasePublisher
{
// compiling
typedef BaseSubscriber<T> SubscriberTypeT;
};
template< class SubscriberT > class ClassA : SubscriberT {};
template< class PublisherT >
class ClassB : PublisherT {
void method1( ClassA<typename PublisherT::SubscriberTypeT> );
};

Reducing number of template arguments for class

I have a method and two classes defined like this:
template<template<class X> class T>
void doSomething()
{
T<int> x;
}
template <class T>
class ClassWithOneArg
{
T t;
};
template <class T1, class T2>
class ClassWithTwoArgs
{
T1 t1;
T2 t2;
};
I can now
doSomething<ClassWithOneArg>();
but I cannot
doSomething<ClassWithTwoArgs>();
However, I'd like to pass ClassWithTwoArgs to doSomething, where T2 = double.
The only method I found is to create
template <class T1>
class ClassWithTwoArgs_Child
: public ClassWithTwoArgs<T1, double>
{
};
and then
doSomething<ClassWithTwoArgs_Child>();
This works, but in my concrete case all classes require a constructor argument and thus I have to create a constructor with this argument also in the _Child-class and pass it to the base which I really want to avoid.
Do you have an idea how to do that?
Thanks a lot!
Indirection is a solution. Instead of a template template parameter you pass a "meta function" -- a function that maps one type to another in form of a struct with a nested class template:
struct mf1 {
template<class Arg1>
struct eval {
typedef ClassTemplateWithOneArg<Arg1> type;
};
};
template<class Arg2>
struct mf2 {
template<class Arg1>
struct eval {
typedef ClassTemplateWithTwoArgs<Arg1,Arg2> type;
};
};
template<class MetaFunc>
void do_something()
{
typedef typename MetaFunc::template eval<int>::type clazztype;
clazztype x;
}
void foo() {
do_something<mf1>();
do_something<mf2<double> >();
}
In C++0x this could be reduced to a "template typedef":
template<class Arg1>
using NewClassTemplate = ClassTemplateWithTwoArgs<Arg1,double>;
which allows you to pass NewClassTemplate as a template template argument which also accepts only one template parameter.
There is no generic solution. Your best bet is
template<class T>
void doSomething()
{
T x;
}
template <class T>
class ClassWithOneArg
{
T t;
};
template <class T1, class T2 = double>
class ClassWithTwoArgs
{
T1 t1;
T2 t2;
};
int main(){
doSomething<ClassWithOneArg<int>>();
doSomething<ClassWithTwoArgs<int, double> >();
}
It seems that what you are after is similar to the rebinding of allocators (given an allocator, containers need to be able to produce an allocator for a different type - e.g std::list<int> might need a allocator<list_node<int> > from allocator<int>.
However, the class templates would have to be modified for this.
template<class T>
void doSomething(const T&)
{
typename T::template rebind_1st<int>::type x;
}
template <class T>
class ClassWithOneArg
{
T t;
public:
template <class U>
struct rebind_1st { typedef ClassWithOneArg<U> type; };
};
template <class T1, class T2>
class ClassWithTwoArgs
{
T1 t1;
T2 t2;
public:
template <class U>
struct rebind_1st { typedef ClassWithTwoArgs<U, T2> type; };
};
int main()
{
doSomething(ClassWithOneArg<char>());
doSomething(ClassWithTwoArgs<char, double>() );
}
Assuming you want declare template instantiations of the same class with a different type for the first template parameter, it appears a version of visitor's code is possible that doesn't require modifying original classes.
template <class T, class NewFirstArg>
struct rebind_1st;
template <template <class> class T, class Arg1, class NewFirstArg>
struct rebind_1st<T<Arg1>, NewFirstArg>
{
typedef T<NewFirstArg> type;
};
template <template <class, class> class T, class Arg1, class Arg2, class NewFirstArg>
struct rebind_1st<T<Arg1, Arg2>, NewFirstArg>
{
typedef T<NewFirstArg, Arg2> type;
};
template <class T>
void foo()
{
typename rebind_1st<T, int>::type x;
(void)x;
}
template <class T>
struct One{};
template <class T1, class T2>
struct Two{};
int main()
{
foo<One<char> >();
foo<Two<char, double> >();
}
This works with MSVC:
template<class T>
void doSomething()
{
T x;
}
// class definitions omitted...
void test() {
doSomething<ClassWithOneArg<int> >();
doSomething<ClassWIthTwoArgs<int, double> >();
}
I do not fully understand why you want to define the first parameter of your template template parameter to be int inside of doSomething. Looks like a "template smell" to me, since doSomething has to know a lot about its template template parameter.
Wouldn't it be cleaner to call doSomething the way i proposed? (But obviously i don't know the context of your calls).

How do we typedef or redefine a templated nested class in the subclass?

Consider the following:
template <typename T>
class Base {
public:
template <typename U>
class Nested { };
};
template <typename T>
class Derived : public Base<T> {
public:
//How do we typedef of redefine Base<T>::Nested?
using Base<T>::Nested; //This does not work
using Base<T>::template<typename U> Nested; //Cannot do this either
typedef typename Base<T>::template<typename U> Nested Nested; //Nope..
//now we want to use the Nested class here
template <typename U>
Class NestedDerived : public Nested { };
//or like this:
Nested<int> nestedVar; // obviously does not work
};
How to use the templated Nested class in the Derived class? Is this possible to do in current version of C++ standard?
Actually using works as advertised, it just doesn't get rid of the dependent-name issue in the template and it can't currently alias templates directly (will be fixed in C++0x):
template <class T>
struct Base {
template <class U> struct Nested {};
};
template <class T>
struct Derived : Base<T> {
using Base<T>::Nested;
// need to prefix Nested with template because
// it is a dependent template:
struct X : Base<T>::template Nested<int> {};
// same here:
template<class U>
struct Y : Base<T>::template Nested<U> {};
// data member, typename is needed here:
typename Base<T>::template Nested<int> data;
};
void f() {
Derived<int>::Nested<int> n; // works fine outside
}
There is another possible gotcha when using Derived<T>::Nested in templates, but again that is a dependent-name issue, not inheritance-related:
template<class T>
void g() {
// Nested is a dependent type and a dependent template, thus
// we need 'typename' and 'template':
typedef typename Derived<T>::template Nested<int> NestedInt;
}
Just remember that names that depend on template arguments have to be
prefixed with typename if its a dependent type: typename A<T>::B
directly prefixed with template if its a dependent template: A<T>::template f<int>()
both if both: typename A<T>::template B<int>
typename is illegal in base-class-lists: template<class T> struct A : B<T>, C<T>::template D<int> {};
This seems to work:
(EDIT: added some more lines to show the first template statement. And thanks to Samir Talwar for correcting my formatting!)
template <typename T, typename U>
class Derived : public Base<T> {
public:
typedef typename Base<T>::template Nested<U> Nested;
class NestedDerived : public Nested { };
Nested nestedVar;
};
Try this:
template <typename T>
class Base {
public:
template <typename U>
class Nested { };
};
template <typename T>
class Derived : public Base<T> {
public:
//How do we typedef of redefine Base<T>::Nested?
//using Base<T>::Nested; //This does not work
//using Base<T>::template<typename U> Nested; //Cannot do this either
//typedef typename Base<T>::template<typename U> Nested Nested; //Nope..
//now we want to use the Nested class here
template <typename U>
class NestedDerived : public Base<T>::template Nested<U> { };
};
int main()
{
Base<int>::Nested<double> nested;
Derived<int>::NestedDerived<double> nested_derived;
return 0;
}
Compiled fine using gcc 4.3.3 on slackware 13
I'm still not 100% sure what you want, but you could try.
This compiled on Visual Studio
template <typename T>
class Base {
public:
template <typename U>
class Nested { };
};
template <typename T>
class Derived : public Base<T> {
public:
//now we want to use the Nested class here
template <typename U>
class NestedDerived : public Nested<U> { };
};
int _tmain(int argc, _TCHAR* argv[])
{
Base<int>::Nested<double> blah2;
Derived<int>::NestedDerived<int> blah;
return 0;
}