can templates be used to detect inheritance relationship - c++

Suppose I have the following code (C++):
template < class Td, class Ud, class Vd>
class Extractor
{
private:
// some code here
public:
// the class has functions to populate these vectors
vector<Td* > list_of_layers;
vector<Ud* > list_of_resistors;
vector<Vd* > list_of_nodes;
}
I wish to impose the restriction that the classes that are used to replace Td, Ud and Vd while instantiating an object of class Extractor are ALWAYS derived from classes (say) T, U and V, respectively. Is it possible?

You could use type_traits and in particular enable_if in combination with is_base_of like the example below:
#include <type_traits>
class BaseT {};
class BaseU {};
class BaseV {};
class DerivedT : public BaseT {};
class DerivedU : public BaseU {};
class DerivedV : public BaseV {};
template < class Td, class Ud, class Vd, class Enable = void>
class Extractor {
static_assert(std::is_base_of<BaseT, Td>::value, "Template argument Td is not derived from BaseT");
static_assert(std::is_base_of<BaseU, Ud>::value, "Template argument Ud is not derived from BaseU");
static_assert(std::is_base_of<BaseV, Vd>::value, "Template argument Vd is not derived from BaseV");
};
template <class Td, class Ud, class Vd>
class Extractor<Td, Ud, Vd,
typename std::enable_if<std::is_base_of<BaseT, Td>::value &&
std::is_base_of<BaseU, Ud>::value &&
std::is_base_of<BaseV, Vd>::value>::type> {
};
int main() {
Extractor<DerivedT, DerivedU, DerivedV> dummy;
Extractor<int, double, int> dummy2; // will fail to compile!!!
}
LIVE DEMO

Yes. You can use the std::is_base_of trait for that.
Add static assertions to your class, e.g.:
static_assert(std::is_base_of<T, Td>::value, "Td must inherit from T");

Related

Can I get name / reference to specialization value inside template specialization?

My code:
enum class list{one, two};
template <list T> class Base;
template <> class Base <list::one>{
A a{list::one};
B b{list::one};
C c{list::one};
};
template <> class Base <list::two>{
B b{list::two};
C c{list::two};
D d{list::two};
};
But I would like to avoid duplicating code, and use reference to specialization value, like this:
template <> class Base <list::one>{
A a{T};
B b{T};
C c{T};
};
template <> class Base <list::two>{
B b{T};
C c{T};
D d{T};
};
I can make sludge temporary variable, but does not look good too:
template <> class Base <list::one>{
list T = list::one;
A a{T};
B b{T};
C c{T};
};
Is there are any way to get reference to template specialization value?
In the following example I'm using SFINAE to make T available in the definition of Base. Specifically I have done the following:
added one dummy type parameter to the primary template,
made the two specialization partial by not specifying the parameter T (and specifying the second dummy type parameter),
specified the second dummy type parameter enforcing that T is equal to list::one and list::two in the two specializations, via std::enable_if_t.
#include <iostream>
#include <type_traits>
enum class list{one, two};
// to make the code compile
class A { public: A(list) {} };
class B { public: B(list) {} };
class C { public: C(list) {} };
class D { public: D(list) {} };
// primary template (second param's sole purpose is to allow partial spec.)
template <list T, typename = void>
class Base;
// partial specialization #1
template <list T>
class Base <T, std::enable_if_t<T == list::one>>{
A a{T};
B b{T};
C c{T};
public:
Base() { std::cout << "list::one\n"; }
};
// partial specialization #2
template <list T>
class Base <T, std::enable_if_t<T == list::two>>{
B b{T};
C c{T};
D d{T};
public:
Base() { std::cout << "list::two\n"; }
};
int main() {
Base<list::one> o;
Base<list::two> t;
}
This is a pretty standard way of using taking advantage of SFINAE via std::enable_if. Similar examples can be found on cppreference page on std::enable_if, where the last example (the one with the first comment // primary template) resambles the code above.

define a class `MultiInherit<MyTuple<X1,X2,...>>` to inherit from `X1,X2,...`

How to define a class MultiInherit<MyTuple<X1,X2,...>> to inherit from X1,X2,... ?
I want to pass MyTuple<X1,X2,...> around to compose a new object type.
template <class... Xs> class MyTuple{};
template <class MyTupleXs> class MultiInherit : public All_Xs_in_MyTupleXs { //??
};
Here is its usage and MCVE (uncompilable):-
class B{public: int b;};
class C{public: int c;};
class BC : public MultiInherit<MyTuple<B,C>> {
public: void testCompile(){
this->b=this->c;
}
};
int main(){
}
Attempt 1
Below is the closest to what I wanted.
If I get raw-types (e.g. B,C) as template argumant rather than MyTuple<B,C>, it would be easy :-
(MCVE, compilable)
template <class... Xs> class MultiInherit : public Xs... {
};
class B{public: int b;};
class C{public: int c;};
class BC : public MultiInherit<B,C> {
public: void testCompile(){
this->b=this->c;
}
};
Reference: Variadic templates and multiple inheritance in c++11
This doesn't solve. I want to pass an encapsulated type MyTuple<B,C>, not the B,C.
Attempt 2
I thought about adding a new variadic typedef MyXs in MyTuple:-
template <class... Xs> class MyTuple{
public: using MyXs=Xs...;
};
template <class MyTupleXs> class MultiInherit : public MyTupleXs::MyXs {
};
Nevertheless, it seems to me that the language has no such feature.
(I am new to variadic template.)
Simple answer
You have to create a template specialization of MultiInherit. Let's look at the base case of MultiInherit:
template<class... Xs>
class MultiInherit : public Xs... {
// Stuff
};
Here, we take a bunch of types and inherit from them. But we can use a template specialization to unpack tuples:
// Specialization on MyTuple
template<class... Xs>
class MultiInherit<MyTuple<Xs...>> : public Xs... {
// Stuff
};
This allows you to do what you want. Given a MyTuple, you have a MultiInherit class that inherits from all the members.
More general case
Defining a type list. If you want to do things more generally, it'll be useful to do them based on templates representing type lists. We can define a template to represent a type list:
template<class...>
struct TypeList {};
Concatenating type lists. We can define more templates to concatenate type lists. ConcatLists is a function that takes two type lists, and returns a TypeList that concatenates them:
template<class... Xs, class... Ys>
TypeList<Xs..., Ys...> ConcatLists(TypeList<Xs...>, TypeList<Ys...>) {
return {};
}
We can use that to define a concat_t that does that automatically:
template<class TypeListA, class TypeListB>
using concat_t = decltype(ConcatLists(TypeListA{}, TypeListB{}));
Substituting MultiInherit for TypeList. We can also substitute one type for another type using template specializations.
// Base case
template<template<class...> class Replacement, class List>
struct SubstituteList;
template<
template<class...> class Replacement,
template<class...> class Original,
class... Xs>
struct SubstituteList<Replacement, Original<Xs...>> {
using type = Replacement<Xs...>;
};
template<template<class...> class Replacement, class List>
using substitute_list_t = typename SubstituteList<Replacement, List>::type;
This means that you can take a TypeList and replace it with a MultiInherit:
template<class ListOfTypes>
using MultiInheritFromTypeList = substitute_list_t<MultiInherit, ListOfTypes>;
Example usage. If you want to convert a TypeList to a MultiInherit:
using T1 = TypeList<int, char, bool>;
// T2 is MultiInherit<int, char, bool>;
using T2 = MultiInheritFromTypeList<T1>;
Example with concat. Or, if you want to concat multiple TypeLists and convert it to a MultiInherit:
using T1 = TypeList<int, char, bool>;
using T2 = TypeList<double, float>;
// T3 is MuliInherit<int, char, bool, double, float>
using T3 = MultiInheritFromTypeList<concat_t<T1, T2>>;

inherit type_trait of Derived in CRTP : type of Derived is not complete (yet)

Library code
My library has a CRTP class B<Derived>.
I created a Trait<T> class to enable user to change behavior of B.
The default setting is int. (#1)
#include <iostream>
#include <string>
//B and Trait (library class)
template<class Derived> class B;
template<class T>class Trait{
public: using type = int; //<-- default setting //#1
};
template<class Derived> class B{
public: using type = typename Trait<Derived>::type; //#2
public: type f(){return 1;}
};
User code ( full coliru demo )
Then, I create a new class C with a new setting std::string. (#3)
It works fine.
//C (user1's class)
template<class Derived> class C ;
template<class Derived>class Trait<C<Derived>>{
public: using type = std::string; //#3
};
template<class Derived> class C : public B<Derived>{};
Finally, I create a new class D.
I want D to derive C's setting i.e. std::string (not int).
However, it is not compilable at $.
//D (user2's class)
class D : public C<D>{ //#4
public: type f(){return "OK";} //#5
//$ invalid conversion from 'const char*' to 'B<D>::type {aka int}'
};
int main(){
D dt;
std::cout<< dt.f() <<std::endl;
}
My understanding
Roughly speaking, here is my understanding about the compile process :-
Just before class D (#4), it doesn't know about D.
At #4, to identity D::type, it looks up C<D>::type.
Finally, it finds that it is defined in B<D>::type at #2.
From #2, it travels to the definition at #1 and find type = int.
Thus D::type = int.
Note that #3 is ignored, because at this point (#4 and #5), D is still incomplete.
The compiler still doesn't fully recognize that D is derived from C<something> ... yet.
Question
How to let D automatically inherit Trait's setting from C without explicitly define another template specialization Trait<D>?
In other words, how to make #3 not ignored for D?
Trait is probably not a good design (?), but I prefer to let the type setting be in a separate trait class.
The instantiating goes like this:
D -> C<D> -> B<D> -> Traits<D>
Traits<D> does not match you partial specialization of Traits<C<Derived>>
If you change it to template<class Derived> class C : public B<C<Derived>>{}; that will in turn instantiate Traits<C<D>> and that will match your specialization and you get std::string as type.
To get the child from B you can use.
template <typename... T>
struct getChild;
template <template <typename... T> typename First, typename... Rest>
struct getChild<First<Rest...>> { using child = typename getChild<Rest...>::child; };
template <typename First>
struct getChild<First> { using child = First; };
and then add in
template<class Derived> class B{
public: using type = typename Trait<Derived>::type;
using child = typename getChild<Derived>::child;
public: type f(){return 1;}
};

What is the base class exactly in this case?

What is the base class exactly in this case?
I have some difficulty to grab the full meaning of the first inheritance, due to the FieldType::template and RecordPolicy<N>
template<
class N,
class FieldType
>
class FieldDefinition:
public FieldType::template RecordPolicy<N>
{
public:
typedef typename FieldType::GetSetPolicy::Type Type;
typedef typename FieldType::GetSetPolicy::MemoryType MemoryType;
typedef FieldType FieldClass;
};
Usage:
template<class ObjectClass_, class Schema_>
class Object:
public virtual ObjectBase,
public FieldDefinition<ObjectClass_, PointerField<ObjectClass_> >
{
//...
}
Others:
template<class T> class PointerField;
template<class T>
class PointerField
{
public:
//...
template<class N>
class RecordPolicy : public SerializedField<N, PointerField<T> > {};
};
The full hierarchy of Object<Foo, Bar> is:
Object<Foo, Bar>
virtual ObjectBase
FieldDefinition<Foo, PointerField<Foo>>
PointerField<Foo>::RecordPolicy<Foo>
SerializedField<Foo, PointerField<Foo>>
In particular, note that FieldType::template RecordPolicy<N> base clause. This means that FieldDefinition expects whatever class is supplied as FieldType (in your case, PointerField<Foo>) to have a nested template named RecordPolicy with a single type template parameter, for which N (in your case, Foo again) will be substituted. The class derives from the result of this instantiation, in your case the nested class PointerField<Foo>::RecordPolicy<Foo>, which in turn has another base class.

typedefs from the template parameter of template class are invisible

Given a base class, that contains the public static method with the general logic for all the derived classes (such as creating them). Parametrizing types of child class template are passed to the base class template (along with the type of the child class in order to have access to its custom static methods in the static method of the base class). From combinations of these types are typedefed new "types" (this is done in the base class to avoid a duplication of some code). They then re-typedefed (similar) in public sections of derived classes. I would use these type definitions into the class containing the helpers, as follows:
#include <iostream>
#include <vector>
#include <cmath>
#include <cstdlib>
template< class DERIVED >
class HELPERS;
template< class V, class DERIVED >
struct BASE
{
typedef typename V::value_type F;
static
F some_common_operation()
{
return helpers.approximate_x(DERIVED::value()); // some common logic (HELPERS::approximate_x() here) depending on the value of DERIVED::value()
}
static
DERIVED create_biased(F const & x)
{
return DERIVED(F(0.5) * (x + some_common_operation()));
}
protected :
BASE(F const & x_)
: x(x_)
{ ; }
F x;
private :
static
HELPERS< DERIVED > const helpers;
};
template< class V, class DERIVED >
HELPERS< DERIVED > const BASE< V, DERIVED >::helpers;
template< class V >
class DERIVED
: public BASE< V, DERIVED< V > >
{
typedef BASE< V, DERIVED< V > > B;
friend B;
public :
typedef typename B::F F;
DERIVED(F const & x_)
: B(x_)
{ ; }
F shape(F const & y) const
{
return y * x;
}
private :
static constexpr
F value()
{
return F(2.0L); // custom data
}
using B::x;
};
// template< class > class DERIVED1;...
template< class D >
struct HELPERS // set of helpers, that operates on classes derived from BASE
{
typedef typename D::F F; // error: no type named <F> in <class DERIVED<std::vector<double> >>
F approximate_x(F const & x) const
{
using std::sqrt;
return sqrt(x);
}
};
int main()
{
DERIVED< std::vector< double > > d(2.0L);
return EXIT_SUCCESS;
}
I'm trying to get the definition in the helpers class, but I get an error (g++ -std=gnu++11 a.cpp).
a.cpp: In instantiation of «struct HELPERS<DERIVED<std::vector<double> > >»:
a.cpp:44:26: required from «struct BASE<std::vector<double>, DERIVED<std::vector<double> > >»
a.cpp:47:7: required from «class DERIVED<std::vector<double> >»
a.cpp:97:39: required from here
a.cpp:85:27: error: no type named «F» in «class DERIVED<std::vector<double> >»
What is wrong? Typedef and all its "ancestors" are accessible (placed in public sections) in the chain of classes.
This is a chicken egg problem.
It is happening because at the time you define BASE, DERIVED is not fully defined yet (because the compiler needs to resolve the base class first). Hence, you can't access any typedefs of DERIVED in HELPER. To make sure you can check the following is not working as well:
template< class V, class DERIVED >
struct BASE
{
typedef typename V::value_type F;
typedef typename DERIVED::F G; // <-- error here
...
}
What you can try is move the use of HELPER to DERIVED, or use V as the parameter for HELPER.