I'm trying to write a template class that defines its template based on the template implementation of a interface. To clarify my problem, here a example.
template<typename T>
class A{
virtual T getValue() = 0;
}
class B : public A<int>{
//does some things and implements getValue
}
//template definition
//T should become int by passing class B
class C{
A* aPointer;
T previousValue;
}
I've tried template template (not a typing error) syntax, explained really nice in this post. What are some uses of template template parameters in C++?. But because the type of A is determent in the definition of B it doesn't work.
How should i go about and create a template that determines T.
You can't determine the type of T directly from B, but you can from its interface. The best way of handling this would be to add a typedef of T to A.
template<typename T>
class A{
virtual T getValue() = 0;
public:
typedef T ValueType;
}
class B : public A<int>{
//does some things and implements getValue
}
template<class T>
class C {
A<typename T::ValueType>* aPointer;
typename T::ValueType previousValue;
}
Define a named type alias in class interfaces.
The standard library also does this.
template<typename T>
class A{
public:
using value_type = T;
virtual value_type getValue() = 0;
};
class B : public A<int>{
public:
using A<int>::value_type;
//does some things and implements getValue
value_type getValue() override { return 0; }
};
//template definition
//T should become int by passing class B
template<class Derived>
class C{
public:
using value_type = typename Derived::value_type;
A<value_type>* aPointer;
value_type previousValue;
};
int main()
{
C<B> c;
auto x = c.aPointer->getValue();
}
You can use a support function of which you don't even have to give a definition.
It follows a minimal, working example:
#include<type_traits>
#include<utility>
template<typename T>
class A{};
class B : public A<int>{};
template<typename T>
T a_type(const A<T> &);
template<typename T>
class C {
public:
using type = decltype(a_type(std::declval<T>()));
};
int main() {
static_assert(std::is_same<C<B>::type, int>::value, "!");
}
The good part of this approach is that you don't have to modify neither A nor B.
Related
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.
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.
Suppose I have a class like so:
template<class T>
class Base{ };
Suppose I have another class like so:
template<class T, class Other>
class Derived :
public virtual Base<T>,
public virtual OtherRandomClass<Other>
{ };
Is there some way to create a template class to determine which version of Base (if any) a random class like Derived is derived from?
Here is a possible solution (working since C++11 - well, it works with C++14, but it does it with C++11 if you use Base<T> instead of auto as a return type for f):
#include<utility>
#include<type_traits>
template<class T>
class Base{ };
template<class T>
class OtherRandomClass{ };
template<class T, class Other>
class Derived :
public virtual Base<T>,
public virtual OtherRandomClass<Other>
{ };
template<typename T>
constexpr auto f(const Base<T> &b) { return b; }
template<typename T>
struct S {
using type = decltype(f(std::declval<T>()));
};
int main() {
static_assert(std::is_same<typename S<Derived<int, double>>::type, Base<int>>::value, "!");
}
It doesn't work if Derived inherits more than once from Base.
Using sfinae (something like the void_t idiom) one can even design a class that works similarly to enable_if: it has type only if T actually inherits from Base once.
It would have the following form:
template<typename T>
constexpr auto f(const Base<T> &b) { return b; }
template<typename...>
using void_t = void;
template<typename T, typename = void_t<>>
struct S { };
template<typename T>
struct S<T, void_t<decltype(f(std::declval<T>()))>> {
using type = decltype(f(std::declval<T>()));
};
This struct can be used at compile time for any template trickery you can imagine.
In both cases, S::type (if it exists) is the type of the base class from which Derived inherits, that is Base<T>.
See the static_assert in the main function of the example for further details.
#include <iostream>
#include <typeinfo>
// placeholder template
template<class SomeDerived> struct traits {};
template<class T>
class Base{ };
template<class T>
class OtherRandomClass{ };
template<class T, class Other>
class Derived :
public virtual Base<T>,
public virtual OtherRandomClass<Other>
{ };
// specialise for our class to provide introspection
template<
class T1,
class T2>
struct traits<
Derived<T1, T2>
>
{
using t1_type = T1;
using first_base_type = Base<T1>;
};
int main()
{
Derived<int, float> x;
using mytraits = traits<decltype(x)>;
std::cout << typeid(mytraits::t1_type).name() << std::endl;
std::cout << typeid(mytraits::first_base_type).name() << std::endl;
}
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.