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.
Related
Consider the code below:
template <typename T>
class A{
...
}
template <class U>
class B{
...
}
int main {
B<A<int>> a;
...
}
How can I get the template parameter of A (int in this case) inside B, if A<int> is the template parameter for B?
I could parametrize B as follows, but I feel like I am sending an unnecessary piece of information.
template <class AA, typename T>
class B { ... }
The reason I do not simply use template <typename T> for class B is that I have a pointer to class A inside B, and I want to use the template parameter class AA to see if that pointer is const or not, hence have the correct type for the member pointer in B.
There are several ways, depending of that you might change:
Quick way, specialize B
template <class> class B;
template <class T>
class B<A<T>>
{
// Use directly T
//...
};
Add info in A directly (as std containers do with value_type)
template <typename T>
struct A
{
using my_type = T;
};
// Then in `B<U>`, use `typename U::my_type`
Use external traits to extract information from A (as std::iterator_traits) (that also allows to handle built-in types):
template <typename T>
struct ATrait;
template <typename T>
struct ATrait<A<T>>
{
using my_type = T;
};
// Possibly a generic one
template <template <typename> class C, typename T>
struct ATrait<C<T>>
{
using my_type = T;
};
// Then in `B<U>`, use `typename ATrait<U>::my_type`
I think the following does what you want:
#include<type_traits>
template<class>
class A{};
template<class>
struct get_inner;
template<template<class> class TT, class T>
struct get_inner<TT<T>> {
using outer = TT<T>;
using inner = T;
};
template<class TT>
struct B {
using A = TT;
using inner = typename get_inner<std::decay_t<A>>::inner;
};
int main(int argc, char *argv[])
{
static_assert(std::is_const_v<typename B<const A<int>>::A>);
static_assert(!std::is_const_v<typename B<A<int>>::A>);
}
Note the std::decay_t, it wouldn't work with the const parameter directly (hence we cannot just specialize B in this way). Maybe decay_t is a bit strong but it works^^
Try this
template <typename X> class B;
template <template <typename> class XX, typename T>
class B<XX<T>>
{
// your implementation
};
B<A<int>> a;
I read the Wikipedia article about the curiously recurring template pattern in C++ for doing static (read: compile-time) polymorphism. I wanted to generalize it so that I could change the return types of the functions based on the derived type. (This seems like it should be possible since the base type knows the derived type from the template parameter). Unfortunately, the following code won't compile using MSVC 2010 (I don't have easy access to gcc right now so I haven't tried it yet). Anyone know why?
template <typename derived_t>
class base {
public:
typedef typename derived_t::value_type value_type;
value_type foo() {
return static_cast<derived_t*>(this)->foo();
}
};
template <typename T>
class derived : public base<derived<T> > {
public:
typedef T value_type;
value_type foo() {
return T(); //return some T object (assumes T is default constructable)
}
};
int main() {
derived<int> a;
}
BTW, I have a work-around using extra template parameters, but I don't like it---it will get very verbose when passing many types up the inheritance chain.
template <typename derived_t, typename value_type>
class base { ... };
template <typename T>
class derived : public base<derived<T>,T> { ... };
EDIT:
The error message that MSVC 2010 gives in this situation is error C2039: 'value_type' : is not a member of 'derived<T>'
g++ 4.1.2 (via codepad.org) says error: no type named 'value_type' in 'class derived<int>'
derived is incomplete when you use it as a template argument to base in its base classes list.
A common workaround is to use a traits class template. Here's your example, traitsified. This shows how you can use both types and functions from the derived class through the traits.
// Declare a base_traits traits class template:
template <typename derived_t>
struct base_traits;
// Define the base class that uses the traits:
template <typename derived_t>
struct base {
typedef typename base_traits<derived_t>::value_type value_type;
value_type base_foo() {
return base_traits<derived_t>::call_foo(static_cast<derived_t*>(this));
}
};
// Define the derived class; it can use the traits too:
template <typename T>
struct derived : base<derived<T> > {
typedef typename base_traits<derived>::value_type value_type;
value_type derived_foo() {
return value_type();
}
};
// Declare and define a base_traits specialization for derived:
template <typename T>
struct base_traits<derived<T> > {
typedef T value_type;
static value_type call_foo(derived<T>* x) {
return x->derived_foo();
}
};
You just need to specialize base_traits for any types that you use for the template argument derived_t of base and make sure that each specialization provides all of the members that base requires.
One small drawback of using traits is that you have to declare one for each derived class. You can write a less verbose and redondant workaround like this :
template <template <typename> class Derived, typename T>
class base {
public:
typedef T value_type;
value_type foo() {
return static_cast<Derived<T>*>(this)->foo();
}
};
template <typename T>
class Derived : public base<Derived, T> {
public:
typedef T value_type;
value_type foo() {
return T(); //return some T object (assumes T is default constructable)
}
};
int main() {
Derived<int> a;
}
In C++14 you could remove the typedef and use function auto return type deduction:
template <typename derived_t>
class base {
public:
auto foo() {
return static_cast<derived_t*>(this)->foo();
}
};
This works because the deduction of the return type of base::foo is delayed until derived_t is complete.
An alternative to type traits that requires less boilerplate is to nest your derived class inside a wrapper class that holds your typedefs (or using's) and pass the wrapper as a template argument to your base class.
template <typename Outer>
struct base {
using derived = typename Outer::derived;
using value_type = typename Outer::value_type;
value_type base_func(int x) {
return static_cast<derived *>(this)->derived_func(x);
}
};
// outer holds our typedefs, derived does the rest
template <typename T>
struct outer {
using value_type = T;
struct derived : public base<outer> { // outer is now complete
value_type derived_func(int x) { return 5 * x; }
};
};
// If you want you can give it a better name
template <typename T>
using NicerName = typename outer<T>::derived;
int main() {
NicerName<long long> obj;
return obj.base_func(5);
}
I know that this is basically the workaround you found and don't like, but I wanted to document it and also to say that it is basically the current solution to this problem.
I have been looking for a way to do this for a while and never found a good solution.
The fact that it is not possible is the reason why ultimately, things like boost::iterator_facade<Self, different_type, value_type, ...> need many parameters.
Of course we would like something something like this to work:
template<class CRTP>
struct incrementable{
void operator++(){static_cast<CRTP&>(*this).increment();}
using ptr_type = typename CRTP::value_type*; // doesn't work, A is incomplete
};
template<class T>
struct A : incrementable<A<T>>{
void increment(){}
using value_type = T;
value_type f() const{return value_type{};}
};
int main(){A<double> a; ++a;}
If this was possible, all the traits of the derived class could be passed implicitly ot the base class. The idiom I found to get the same effect is to pass the traits to the base class entirely.
template<class CRTP, class ValueType>
struct incrementable{
void operator++(){static_cast<CRTP&>(*this).increment();}
using value_type = ValueType;
using ptr_type = value_type*;
};
template<class T>
struct A : incrementable<A<T>, T>{
void increment(){}
typename A::value_type f() const{return typename A::value_type{};}
// using value_type = typename A::value_type;
// value_type f() const{return value_type{};}
};
int main(){A<double> a; ++a;}
https://godbolt.org/z/2G4w7d
The drawback is that the trait in the derived class has to be accessed with a qualified typename or reenabled by using.
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>
I read the Wikipedia article about the curiously recurring template pattern in C++ for doing static (read: compile-time) polymorphism. I wanted to generalize it so that I could change the return types of the functions based on the derived type. (This seems like it should be possible since the base type knows the derived type from the template parameter). Unfortunately, the following code won't compile using MSVC 2010 (I don't have easy access to gcc right now so I haven't tried it yet). Anyone know why?
template <typename derived_t>
class base {
public:
typedef typename derived_t::value_type value_type;
value_type foo() {
return static_cast<derived_t*>(this)->foo();
}
};
template <typename T>
class derived : public base<derived<T> > {
public:
typedef T value_type;
value_type foo() {
return T(); //return some T object (assumes T is default constructable)
}
};
int main() {
derived<int> a;
}
BTW, I have a work-around using extra template parameters, but I don't like it---it will get very verbose when passing many types up the inheritance chain.
template <typename derived_t, typename value_type>
class base { ... };
template <typename T>
class derived : public base<derived<T>,T> { ... };
EDIT:
The error message that MSVC 2010 gives in this situation is error C2039: 'value_type' : is not a member of 'derived<T>'
g++ 4.1.2 (via codepad.org) says error: no type named 'value_type' in 'class derived<int>'
derived is incomplete when you use it as a template argument to base in its base classes list.
A common workaround is to use a traits class template. Here's your example, traitsified. This shows how you can use both types and functions from the derived class through the traits.
// Declare a base_traits traits class template:
template <typename derived_t>
struct base_traits;
// Define the base class that uses the traits:
template <typename derived_t>
struct base {
typedef typename base_traits<derived_t>::value_type value_type;
value_type base_foo() {
return base_traits<derived_t>::call_foo(static_cast<derived_t*>(this));
}
};
// Define the derived class; it can use the traits too:
template <typename T>
struct derived : base<derived<T> > {
typedef typename base_traits<derived>::value_type value_type;
value_type derived_foo() {
return value_type();
}
};
// Declare and define a base_traits specialization for derived:
template <typename T>
struct base_traits<derived<T> > {
typedef T value_type;
static value_type call_foo(derived<T>* x) {
return x->derived_foo();
}
};
You just need to specialize base_traits for any types that you use for the template argument derived_t of base and make sure that each specialization provides all of the members that base requires.
One small drawback of using traits is that you have to declare one for each derived class. You can write a less verbose and redondant workaround like this :
template <template <typename> class Derived, typename T>
class base {
public:
typedef T value_type;
value_type foo() {
return static_cast<Derived<T>*>(this)->foo();
}
};
template <typename T>
class Derived : public base<Derived, T> {
public:
typedef T value_type;
value_type foo() {
return T(); //return some T object (assumes T is default constructable)
}
};
int main() {
Derived<int> a;
}
In C++14 you could remove the typedef and use function auto return type deduction:
template <typename derived_t>
class base {
public:
auto foo() {
return static_cast<derived_t*>(this)->foo();
}
};
This works because the deduction of the return type of base::foo is delayed until derived_t is complete.
An alternative to type traits that requires less boilerplate is to nest your derived class inside a wrapper class that holds your typedefs (or using's) and pass the wrapper as a template argument to your base class.
template <typename Outer>
struct base {
using derived = typename Outer::derived;
using value_type = typename Outer::value_type;
value_type base_func(int x) {
return static_cast<derived *>(this)->derived_func(x);
}
};
// outer holds our typedefs, derived does the rest
template <typename T>
struct outer {
using value_type = T;
struct derived : public base<outer> { // outer is now complete
value_type derived_func(int x) { return 5 * x; }
};
};
// If you want you can give it a better name
template <typename T>
using NicerName = typename outer<T>::derived;
int main() {
NicerName<long long> obj;
return obj.base_func(5);
}
I know that this is basically the workaround you found and don't like, but I wanted to document it and also to say that it is basically the current solution to this problem.
I have been looking for a way to do this for a while and never found a good solution.
The fact that it is not possible is the reason why ultimately, things like boost::iterator_facade<Self, different_type, value_type, ...> need many parameters.
Of course we would like something something like this to work:
template<class CRTP>
struct incrementable{
void operator++(){static_cast<CRTP&>(*this).increment();}
using ptr_type = typename CRTP::value_type*; // doesn't work, A is incomplete
};
template<class T>
struct A : incrementable<A<T>>{
void increment(){}
using value_type = T;
value_type f() const{return value_type{};}
};
int main(){A<double> a; ++a;}
If this was possible, all the traits of the derived class could be passed implicitly ot the base class. The idiom I found to get the same effect is to pass the traits to the base class entirely.
template<class CRTP, class ValueType>
struct incrementable{
void operator++(){static_cast<CRTP&>(*this).increment();}
using value_type = ValueType;
using ptr_type = value_type*;
};
template<class T>
struct A : incrementable<A<T>, T>{
void increment(){}
typename A::value_type f() const{return typename A::value_type{};}
// using value_type = typename A::value_type;
// value_type f() const{return value_type{};}
};
int main(){A<double> a; ++a;}
https://godbolt.org/z/2G4w7d
The drawback is that the trait in the derived class has to be accessed with a qualified typename or reenabled by using.
I read the Wikipedia article about the curiously recurring template pattern in C++ for doing static (read: compile-time) polymorphism. I wanted to generalize it so that I could change the return types of the functions based on the derived type. (This seems like it should be possible since the base type knows the derived type from the template parameter). Unfortunately, the following code won't compile using MSVC 2010 (I don't have easy access to gcc right now so I haven't tried it yet). Anyone know why?
template <typename derived_t>
class base {
public:
typedef typename derived_t::value_type value_type;
value_type foo() {
return static_cast<derived_t*>(this)->foo();
}
};
template <typename T>
class derived : public base<derived<T> > {
public:
typedef T value_type;
value_type foo() {
return T(); //return some T object (assumes T is default constructable)
}
};
int main() {
derived<int> a;
}
BTW, I have a work-around using extra template parameters, but I don't like it---it will get very verbose when passing many types up the inheritance chain.
template <typename derived_t, typename value_type>
class base { ... };
template <typename T>
class derived : public base<derived<T>,T> { ... };
EDIT:
The error message that MSVC 2010 gives in this situation is error C2039: 'value_type' : is not a member of 'derived<T>'
g++ 4.1.2 (via codepad.org) says error: no type named 'value_type' in 'class derived<int>'
derived is incomplete when you use it as a template argument to base in its base classes list.
A common workaround is to use a traits class template. Here's your example, traitsified. This shows how you can use both types and functions from the derived class through the traits.
// Declare a base_traits traits class template:
template <typename derived_t>
struct base_traits;
// Define the base class that uses the traits:
template <typename derived_t>
struct base {
typedef typename base_traits<derived_t>::value_type value_type;
value_type base_foo() {
return base_traits<derived_t>::call_foo(static_cast<derived_t*>(this));
}
};
// Define the derived class; it can use the traits too:
template <typename T>
struct derived : base<derived<T> > {
typedef typename base_traits<derived>::value_type value_type;
value_type derived_foo() {
return value_type();
}
};
// Declare and define a base_traits specialization for derived:
template <typename T>
struct base_traits<derived<T> > {
typedef T value_type;
static value_type call_foo(derived<T>* x) {
return x->derived_foo();
}
};
You just need to specialize base_traits for any types that you use for the template argument derived_t of base and make sure that each specialization provides all of the members that base requires.
One small drawback of using traits is that you have to declare one for each derived class. You can write a less verbose and redondant workaround like this :
template <template <typename> class Derived, typename T>
class base {
public:
typedef T value_type;
value_type foo() {
return static_cast<Derived<T>*>(this)->foo();
}
};
template <typename T>
class Derived : public base<Derived, T> {
public:
typedef T value_type;
value_type foo() {
return T(); //return some T object (assumes T is default constructable)
}
};
int main() {
Derived<int> a;
}
In C++14 you could remove the typedef and use function auto return type deduction:
template <typename derived_t>
class base {
public:
auto foo() {
return static_cast<derived_t*>(this)->foo();
}
};
This works because the deduction of the return type of base::foo is delayed until derived_t is complete.
An alternative to type traits that requires less boilerplate is to nest your derived class inside a wrapper class that holds your typedefs (or using's) and pass the wrapper as a template argument to your base class.
template <typename Outer>
struct base {
using derived = typename Outer::derived;
using value_type = typename Outer::value_type;
value_type base_func(int x) {
return static_cast<derived *>(this)->derived_func(x);
}
};
// outer holds our typedefs, derived does the rest
template <typename T>
struct outer {
using value_type = T;
struct derived : public base<outer> { // outer is now complete
value_type derived_func(int x) { return 5 * x; }
};
};
// If you want you can give it a better name
template <typename T>
using NicerName = typename outer<T>::derived;
int main() {
NicerName<long long> obj;
return obj.base_func(5);
}
I know that this is basically the workaround you found and don't like, but I wanted to document it and also to say that it is basically the current solution to this problem.
I have been looking for a way to do this for a while and never found a good solution.
The fact that it is not possible is the reason why ultimately, things like boost::iterator_facade<Self, different_type, value_type, ...> need many parameters.
Of course we would like something something like this to work:
template<class CRTP>
struct incrementable{
void operator++(){static_cast<CRTP&>(*this).increment();}
using ptr_type = typename CRTP::value_type*; // doesn't work, A is incomplete
};
template<class T>
struct A : incrementable<A<T>>{
void increment(){}
using value_type = T;
value_type f() const{return value_type{};}
};
int main(){A<double> a; ++a;}
If this was possible, all the traits of the derived class could be passed implicitly ot the base class. The idiom I found to get the same effect is to pass the traits to the base class entirely.
template<class CRTP, class ValueType>
struct incrementable{
void operator++(){static_cast<CRTP&>(*this).increment();}
using value_type = ValueType;
using ptr_type = value_type*;
};
template<class T>
struct A : incrementable<A<T>, T>{
void increment(){}
typename A::value_type f() const{return typename A::value_type{};}
// using value_type = typename A::value_type;
// value_type f() const{return value_type{};}
};
int main(){A<double> a; ++a;}
https://godbolt.org/z/2G4w7d
The drawback is that the trait in the derived class has to be accessed with a qualified typename or reenabled by using.