Given two templated classes which are very similar but behave differently:
template<class T>
firstBase {};
template<class T>
secondBase {};
Now I've got this other class, which, based on it's template parameter, will derive either from firstBase or from secondBase:
template<class B, class T>
myClass : public B<T> { /* T is used in here */ };
Well, that does not work. The compiler tells me that B is an unknown template name. (error: unknown template name 'B')
My current workaround is to define myClass as
template<class B, class T>
myClass : public B { /* T is used in here */ };
and the caller of myClass needs to intatiate it via myClass<b<t>, t> instead of myClass<b, t>.
The latter would be really nice and reduce some copy&paste code. Is there any other way of achieving this?
In my use case I'm trying to implement a deep_const_ptr for the pimpl idiom enabling 'true constness'. Depending on whether myClass needs to be copy-assignable or not, it either uses deep_const_ptr<std::shared_ptr> or deep_const_ptr<std::unique_ptr> for its private pointer.
#include <memory>
#include <iostream>
template<class pointerT, class typeT>
class deep_const_ptr : public pointerT
{
public:
explicit deep_const_ptr(typeT* ptr) : pointerT(ptr) { }
// overloading pointerT::operator->() for non-constant access
typeT* operator->() {
std::cout << "deep_const_ptr::operator->()" << std::endl;
return pointerT::operator->();
}
// overloading pointerT::operator->() for constant access
const typeT* operator->() const {
std::cout << "deep_const_ptr::operator->() const" << std::endl;
return pointerT::operator->();
}
};
Edit
So I ended up, as suggested by Luc Danton in his answer, passing std::unique_ptr<myClass::Private> or std::shared_ptr<myClass::Private> to my custom deep_const_ptr:
template<typename pointerTypeT>
class deep_const_ptr : public pointerTypeT {
explicit deep_const_ptr(typename pointerTypeT::element_type* ptr) : pointerTypeT(ptr);
typename pointerTypeT::element_type* operator->();
const typename pointerTypeT::element_type* operator->() const;
};
deep_const_ptr<std::unique_ptr<Test::Private>> d_unique;
deep_const_ptr<std::shared_ptr<Test::Private>> d_shared;
What you want is template template parameter:
// vvvvvvvvvvvvvvvvvv
template<template<typename> class B, class T>
class myClass : public B<T> { /* T is used in here */ };
Then, use that like:
myClass<firstBase,int> myIntClassObject;
myClass<secondBase,bool> myBoolClassObject;
For std::unique_ptr, you can make a wrapper:
template<typename T>
class uniquePtr : public std::unique_ptr<T>
{
};
or
template<typename T>
using uniquePtr = std::unique_ptr<T>;
I recommend against template template parameters in general. For instance std::unique_ptr and std::shared_ptr are different in that the former accepts two type parameters and the latter just one. So if you declare e.g. template<template<typename> class B, typename T> class foo; then foo<std::shared_ptr, int> is valid but foo<std::unique_ptr, int> isn't.
In your particular case you could use template<typename...> class B as a parameter, because that kind of template template parameters is special. Still, this would only accept templates that only take type parameters (not even template template parameters). Sometimes this can be worked around with alias templates, sometimes it can't.
In my experience there are better alternatives -- for instance you can conditionally inherit:
template<typename T>
struct pointer: std::conditional</* Make a choice here*/, std::unique_ptr<T>, std::shared_ptr<T>>::type {};
Or why not just accept the smart pointer as the parameter itself:
template<typename Pointer>
struct foo {
Pointer pointer;
/* typename Pointer::element_type plays the role that T used to have */
};
The Standard Library itself takes some steps to avoid template template parameters: have you ever noticed that an std::vector<T> uses std::allocator<T> as an argument, and not std::allocator? As a tradeoff, it means that an Allocator must provide a rebind member alias template.
B should be a template template parameter:
template<template <class> class B, class T>
class myClass : public B<T> { /* T is used in here */ };
Now you can give either firstBase or secondBase as the first template argument because they are templates.
You simply need to use a template-template parameter to get it to work:
template <
template <class> class B, class T>
// ^^^^^^^^^^^^^^^^
class myClass : public B<T> { / ... / };
It seems what you need is template template parameters:
template<template<class> class B, class T>
// ^^^^^^^^^^^^^^^
class myClass : public B<T> { /* T is used in here */ };
Now the first template argument for the myClass class template must be itself a class template that accepts one template (type) parameter. So, putting everything together:
template<class T>
class firstBase {};
template<class T>
class secondBase {};
template<template<class> class B, class T>
class myClass : public B<T> { /* T is used in here */ };
And here is how you would instantiate your myclass template to create a class that derives from firstBase<int>:
myClass<firstBase, int> obj;
Finally, here is a live example.
Related
I am currently struggling with templates: I have a templated class A, which performs basic math (for floats, doubles, complex numbers) and looks like this
template <typename T>
class A
{
public:
void foo(std::vector<std::complex<T>>& result);
};
Now I can use the class like A<double>, A<float>, but I would also like to use it like A<std::complex<float>> and A<std::complex<double>>. When using the latter, I would like the definition of foo to look like
void foo(std::vector<std::complex<float>>& result);
and not like
void foo(std::vector<std::complex<std::complex<float>>>& result);
Is there any way to create a specific template for the std::complex<T> cases, in which I can access the "inner" type? Or this is not possible/bad practice?
What is the most elegant way to solve this issue?
Another way can pass through the creation of a type traits to detect the (extract, when needed) the float type
template <typename T>
struct getFloatType
{ using type = T; };
template <typename T>
struct getFloatType<std::complex<T>>
{ using type = T; };
and use it in A (see fT)
template <typename T>
class A
{
public:
using fT = typename getFloatType<T>::type;
void foo(std::vector<std::complex<fT>>& result)
{ }
};
You can make a partial specialization for any instantiation of std::complex, e.g.
template <typename T>
class A<std::complex<T>>
{
public:
void foo(std::vector<std::complex<T>>& result);
};
Then for A<std::complex<double>>, the signature of foo would be void foo(std::vector<std::complex<double>>& result);.
To handle those duplicated codes, you can make a base class and move the common members into it, and make the primary template and partial specialization both derive from it. e.g.
class Base {
public:
void bar(...);
};
then
template <typename T>
class A : public Base {
...
};
template <typename T>
class A<std::complex<T>> : public Base {
...
};
I have the following template class :
template <typename T>
class myClass
{
public:
// Many methods...
protected:
private:
T attribute
// Other attributes.
};
Instantiating an object of type myClass<void> does not work, because of void attribute.
Can you give me some hints to be able to use objects of type myClass<void> without specializing the whole class. Since it has many member functions that rely on the type T, specializing it will lead to code duplication.
Create a templated base class containing attribute, specialize it for void and inherit from it:
namespace detail //Warn end user that he should not use stuff from here
{
template <typename T>
struct myClass_base
{
T attribute;
};
template <>
struct myClass_base<void>
{}; //No attribute at all
}
template <typename T>
class myClass: private detail::myClass_base<T>
{
//rest of definition
};
This would make myClass lack attribute field when instantiating it with type void
You can defer the whole problem by using a custom type and specializing that:
template<typename T>
struct my_type_t
{
using type = T;
};
template<>
struct my_type_t<void>
{};
template<typename T>
using my_type = typename my_type_t<T>::type;
template <typename T>
class myClass
{
public:
// Many methods...
protected:
private:
my_type<T> attribute
// Other attributes.
};
Then at least you don't have to duplicate the whole rest of the class again.
But it probably does not make that much sense, as you surely want to use the type somewhere. So you would have to specialize that places further.
Suppose I have set of classes inheriting from a single superclass S:
class S{ ... };
class C1 : public S{ ... };
class C2 : public S{ ... };
Then suppose I have a templated method:
template<class T> void foo(T* instance);
I would like to statically check that foo is never called providing an instance of the superclass but only called providing one of the (concrete) subclasses (e.g. explicitly calling foo<C1>(x) for instance)
Is this possible?
First we can write a trait to check if T is derived from S, but not S:
template <class Base, class Derived>
using is_strict_base =
std::integral_constant<bool,
std::is_base_of<Base,Derived>::value &&
!std::is_same<Base,typename std::remove_cv<Derived>::type>::value>;
You can use std::enable_if to use this trait:
template<class T>
typename std::enable_if<is_strict_base<S,T>::value>::type
foo(T* instance)
{}
With C++14 you can use std::enable_if_t to make it a bit prettier:
template<class T>
std::enable_if_t<is_strict_base<S,T>::value>
foo(T* instance)
{}
Another option is to use static_assert:
template<class T>
void foo(T* instance)
{
static_assert(is_strict_base<S,T>::value,
"T must be derived from S, but not S");
}
This gives you a nicer error, but I personally believe that type constraints for a function belong in the declaration.
If I have a base class and its hierarchy :
class BaseClass {
}
class DerivedClass : public BaseClass {
}
And a templated class :
template <class T> struct TemplatedClass {
}
How can I achieve this ? :
// 1:
void doSomething(TemplatedClass<BaseClass *> const &t);
// 2:
std::vector<TemplatedClass<BaseClass *>> v;
TemplatedClass<DerivedClass *> a;
// Doesn't compile
doSomething(a);
// Doesn't compile
v.push_back(a);
You could have your templated classes have a hierarchy, too. You'll need to specify the bases, however:
template <typename...>
struct TC;
template <>
struct TC<> {
virtual ~TC() {}
};
template <typename T, typename... B>
struct TC
: TC<B...> {
// ...
};
With the variadic argument for the inheritance this should allow you specifying the relationship between the templates to mimick the inheritance hierarchy of the underlying. For example:
TC<Base>* d = new TC<Derived, Base>(/*...*/);
You need to make TemplatedClass<DerivedClass*> convertable to TemplatedClass<BaseClass *>, as they are independent types. Best way would be to have constructor, something like this:
template <class T> struct TemplatedClass {
template<class P> TemplatedClass( const TemplatedClass<P> &an );
};
Looks like you are trying to make something like smart pointer, you should look how it is already done on std::shared_ptr or boost::shared_ptr.
If you plan to use this code in production and/or share it with your team you may want to put additional checks on data type passed to this ctor:
template <class T> struct TemplatedClass {
template<class P, class = typename std::enable_if<std::is_convertible<P, T>{}>::type>
TemplatedClass( const TemplatedClass<P> &an );
};
Again best way would be to look into sources of shared_ptr and see how it is done there.
I have the following situation:
I have a object of type MyClass, which has a method to cast itself to its base class. The class includes a typedef for its base class and a method to do the upcast.
template <class T, class B>
class BaseClass;
template <class T>
class NoAccess;
template <class T>
class MyClass : public BaseClass<T, NoAccess<T> >
{
private:
typedef BaseClass<T, NoAccess<T> > base;
public:
base &to_base();
};
I need to pass the result of a base call to a functor Operator:
template <class Y>
class Operator
{
Operator(Y &x);
};
Operator<???> op(myobject.to_base());
Is there a easy way to fill the ??? provided that I do not want to use NoAccess?
You can define a factory function to use type deduction:
template< class Y >
Operator<Y> create_operator( Y &y ) {
return Operator<Y>( y );
}
I see three possibilities:
make MyClass<T,B>::base a public identifier
change your operator and make the constructor a template using type-erasure (might be hard):
class Operator { template<class Y> Operator(Y &x); }
move the code creating the Operator object into its own function template:
template<typename T> Operator<T> createOperator(const T& base)
{return Operator<T>(base);}
You can make the typedef public:
Operator<MyClass<type>::base> op(myobject.to_base());