"virtual" method with templates - c++

I have the following base class :
template <template<class Type> class T2>
class FundamentalClass {
typename T2<double> *_compose1;
typename T2<int> *_compose2;
protected:
FundamentalClass(); // Insert constructors here.
template<class Strategy>
T2<typename Strategy::Type> *Construct(void);
public:
template <class Strategy>
T2<typename Strategy::Type> *GetComposedObject(void);
};
with
template< template<class Type> class T2>
template<>
T2<double> *FundamentalClass<T2<double> >::GetComposedObject<DoubleStrategy>(void) {
if( NULL == _compose1) {
_compose1 = Construct<DoubleStrategy>(void);
}
return _compose1;
}
And other specializations for each composed object.
But, i need construct to be implemented by the derived class. Without templates, Construct whould be virtual. How can i achieve this goal ?

You can do this with compile-time polymorphism, via the Curiously Recurring Template Pattern (CRTP):
template <template<class Type> class T2, class Derived>
class FundamentalClass {
...
template<class Strategy>
T2<typename Strategy::Type> *Construct() {
return static_cast<Derived *>(this)->DoConstruct<Strategy>();
}
And in Derived, write:
template <template<class Type> class T2>
class Derived: public FundamentalClass<T2, Derived<T2> >
{
public:
template<class Strategy>
T2<typename Strategy::Type> *DoConstruct() {
...
}

Related

Not fully specified template as template argument in C++

In curiously recurring template pattern I need to change nested type T of TDerivedClass<T> type. Is there a way to specify Base by not fully specified Derived1 class? Something like that: class Derived1 : public Base<T, Derived1<"NOT SPECIFIED TYPE SYNTAX">>, and then fully specify Derived1 but inside Base functions as TDerivedClass<int>. Or is there any other way to change T for this specific part of code?
template<typename T, typename TDerivedClass>
class Base
{
public:
void f()
{
std::vector<T> a;
TDerivedClass b;
TDerivedClass<int> c; // <- want to change T to arbitrary type (to int for example) without changing T
}
};
template<typename T>
class Derived1 : public Base<T, Derived1<T>>
{
};
template<typename T>
class Derived2 : public Base<T, Derived2<T>>
{
};
You probably want template template parameter:
template <typename T, template <typename> class TDerivedClass>
class Base
{
public:
void f()
{
std::vector<T> a;
TDerivedClass<T> b;
TDerivedClass<int> c;
}
};
template<typename T>
class Derived1 : public Base<T, Derived1>
{
};
template<typename T>
class Derived2 : public Base<T, Derived2>
{
};
You can pass the template class specifically:
template<typename T, template<typename> class TDerivedTemplate>
class Base
{
using TDerivedClass = TDerivedTemplate<T>;
public:
void f()
{
std::vector<T> a;
TDerivedClass b;
TDerivedTemplate<int> c;
}
};
template<typename T>
class Derived1 : public Base<T, Derived1> // Pass the template (Derived1) to instantiate new classes from
{
};
// Since you're changing the pattern anyways, you might as well
// have it detect the template from the type
template<typename TDerivedClass>
class Base;
template<template<typename> class TDerivedTemplate, typename T>
class Base<TDerivedTemplate<T>> {
using TDerivedClass = TDerivedTemplate<T>;
public:
void f() { /* Same as above */ }
}
template<typename T>
class Derived1 : public Base<Derived1<T>>
// Automatically gets the template. Also means it's harder to use Base<> wrong.
{
};
Or you can use a rebind type trait:
template<typename ToRebind, typename... NewTypes>
struct rebind;
template<template<typename...> class Template, typename... CurrentTypes, typename... NewTypes>
struct rebind<Template<CurrentTypes...>, NewTypes...> {
using type = Template<NewTypes...>;
}
// Used like
TDerivedClass b;
typename rebind<TDerivedClass, int>::type c;

Best approach to declare as friend a class template without knowing one its template arguments

I stumbled into a scenario and I'm trying to figure out for the cleanest approach, if there's any.
I have a template class with a protected constructor, that needs to be instantiated by a friend template class. Both share part of template parameters, but not all. Here's a example of my problem.
I wish to know from experienced programmers if there are other possible solutions (I suppose not, besides turning constructor public), and if between the two I present one its more acceptable than the other.
Thanks
Solution 1- I supply "unnecessary" template parameters to the class with protected constructor (class Element).
template <typename Tp_>
class Engine_Type_X
{
};
template <typename Tp_>
class Engine_Type_Z
{
};
//Forward declaration
template <typename Tp_, template<typename> typename Eng_>
class Container;
//Eng_ is only required to declare the friend class
template <typename Tp_,template<typename> typename Eng_>
class Element
{
friend class Container<Tp_,Eng_>;
Tp_ tp_;
protected:
Element(Tp_ tp) : tp_{tp} //protected ctor!!!
{}
};
template <typename Tp_, template<typename> typename Eng_>
class Container
{
using Element_tp = Element<Tp_,Eng_>;
using Engine_tp = Eng_<Tp_>;
std::vector<Element_tp> container_;
Engine_tp &engine_;
public:
Container(Engine_tp &engine) : container_{},engine_{engine}
{}
void install(Tp_ tp)
{ Element_tp elem{tp};
container_.emplace_back(elem);
}
};
Solution 2 - I use an approach like the one I've found here How to declare a templated struct/class as a friend?
template <typename Tp_>
class Engine_Type_X
{
};
template <typename Tp_>
class Engine_Type_Z
{
};
template <typename Tp_>
class Element
{
template<typename,template<typename>typename> friend class Container; //All templated classes are friend
Tp_ tp_;
protected:
Element(Tp_ tp) : tp_{tp} //protected ctor!!!
{}
};
template <typename Tp_, template<typename> typename Eng_>
class Container
{
using Element_tp = Element<Tp_>;
using Engine_tp = Eng_<Tp_>;
std::vector<Element_tp> container_;
Engine_tp &engine_;
public:
Container(Engine_tp &engine) : container_{},engine_{engine}
{}
void install(Tp_ tp)
{ Element_tp elem{tp};
container_.emplace_back(elem);
}
};
You still have some options to explore.
You could make one class an inner class (called nested class), that would automaticly
friend it to the 'outside' class. See https://en.cppreference.com/w/cpp/language/nested_types
Another approach is to require a so called 'token' as a parameter to a
the constructor, this token type doesn't usually take template parameters, then make it so that this token can only be
created by the other class (could be a nested type or friended).
On request from OP, here is an outline of one way to accomplish 2. option: (using c++0x)
template<typename Test, template<typename...> class Ref>
struct is_specialization : std::false_type {};
template<template<typename...> class Ref, typename... Args>
struct is_specialization<Ref<Args...>, Ref>: std::true_type {};
template <class T>
class create_token {
public:
typedef T Type;
//copy of token not allowed !
create_token(const create_token &) = delete;
create_token& operator=(const create_token &) = delete;
//move is fine
create_token(create_token &&) = default;
create_token& operator=(create_token &&) = default;
friend class T;
private:
create_token();
};
template<class BlaBlaBla>
struct Element {
template<class T>
Element(create_token<T> t) {
static_assert(std::is_specialization<create_token<T>::Type, Container>::value, "Wrong type of token provided");
}
};
template<class Whatever>
struct Container {
template<class T>
Element(create_token<T> t) {
static_assert(std::is_specialization<create_token<T>::Type, Element>::value, "Wrong type of token provided");
}
};

Get base derived from

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;
}

Use a template template parameter with CRTP in a Concept

I want to write a concept that tests for inheritance from a base class.
My Base class is publicly inherited by Derived classes, using CRTP.
This code works fine:
#include <type_traits>
namespace NS
{
template<typename D>
class Base {
// ...
};
class Derived : public Base<Derived>
{
public:
constexpr Derived() = default;
// ...
};
}
template<typename D>
concept bool inheritsFromB() {
return std::is_base_of<NS::Base<D>, D>::value;
}
template<inheritsFromB b>
void myFunct() {};
int main() {
constexpr auto d = NS::Derived();
using dType = typename std::decay<decltype(d)>::type;
myFunct<dType>();
}
I hit a problem if I want to template Derived. Is this possible?
namespace NS
{
template<typename D, typename T>
class Base { ... };
template<typename T>
class Derived : public Base<Derived<T>, T>
{ // ...
// probably some using declaration for T?
};
}
template<template <typename> class D>
concept bool inheritsFromB() {
return std::is_base_of<NS::B<D<T>,T>, D<T>::value;
}
...
the obvious problem being that I have no T in my concept declaration.
Moreover, I'm pretty sure I can't declare
template<template <typename> class D, typename T>
concept bool inheritsFromB() {
...
}
because a concept requires one template parameter.
Edit - the Working Paper P0121R0 lists in section 8.3.5, p23, template<typename T, typename U> concept bool C3 = true;. Consequently, wherever I read a concept can take only one parameter was either outdated, wrong, or I read it lacking care. end edit
Can I access the other type(s) T that I need here? Is there an alternative way (it seems to me like the template type D would carry the information of what it's type T is, but I also can't use using T = typename D<T>::valueType;, because I need the T to specific the type of D<T>...)
I suspect the following trait should work:
#include <type_traits>
#include <utility>
namespace NS
{
template <typename D, typename T>
class Base {};
template <typename T>
class Derived : public Base<Derived<T>, T> {};
}
namespace detail
{
template <typename T, template <typename> typename D>
std::true_type is_derived_from_base(const ::NS::Base<D<T>,T>*);
std::false_type is_derived_from_base(void*);
}
template <typename T>
using is_derived_from_base = decltype(detail::is_derived_from_base(std::declval<T*>()));
template <typename T>
concept bool inheritsFromB()
{
return is_derived_from_base<T>{};
}
DEMO (without concepts)

Specialization of a class that uses Policy classes

I wrote the following:
//Policy Classes
template
<typename T>
struct CheckForZeroSpeed
{
};
template
<typename T>
struct NoCheck
{
};
//Specialization for one of the Policy Classes
template
<>
struct NoCheck<float>
{
};
//Class that uses Policy
template
<typename T,template <class C> class Policy>
class Base : public Policy<T>
{
};
//Inherited class that uses Policy
template
<typename T,template <class C> class Policy>
class Derived : public Base<T,Policy>
{
};
How can I declare a specialization of the Base class (let's say for the int type) and a specialization for the Derived class?
This also works:
template
<>
class Base<int,NoCheck>
{
};
But this is a specialization based both on the type and the policy, is it a way to have specialization based only one (type) of the two template parameters? Something like:
//not compile
template
<template <class C> class Policy>
class Base<int,Policy<T>>
{
};
Edit:
The correct is:
//Partial specialization based on the type
template
<template <class C> class Policy>
class Base<int,Policy>
{
};
//Partial specialization based on the Policy
template
<typename T>
class Base<T,NoCheck>
{
};