I've been stuck with templates problems for a few days and you solved each of my problems one at a time so thank you in advance.
I have a template (tl1
) who care about a uml composition
, and another template (tl2
) which is the uml composed
So my goal is to not compile if the composed
object is not a derived
of tl2
and if typename D
is not a tl1 derived
.
Following this post and the help of this one I've got the following code:
#include <type_traits>
#include <list>
#include <string>
template <typename T, typename C>
class tl2 ;
template <typename D, typename T>
class tl1 {
private:
static_assert(std::is_base_of<tl2<T, D>, T>::value, "T should inherit from tl2");
std::list<T> mTs ;
tl1() {} ;
friend D ;
public:
T & getTbyName() const ;
};
template <typename T, typename C>
class tl2 {
//static_assert(std::is_base_of<tl1<C, T>, C>::value, "D should inherit from Database");
public:
std::string getName() { return mName ; }
private:
C & mC ;
std::string mName ;
};
class cl1 ;
class cl2 : public tl2<cl2, int> {
};
class cl1 : public tl1<int, cl2> {
};
My problem is this compiles very well and I would like not.
I would like not compile because D
from tl1<D, T>
must derived
from tl1
.
And actually class cl1 : public tl1<int, cl2>
is not correct but it compiles. So why?
It doesn't compile if I change cl1
to:
class cl1 : public tl1<int, cl2> {
cl1() {}
};
I understand why it doesn't compile after the change, but I do not understand why it compiled before.
The fact is tl1
and tl2
will be in library, so I want to perform all checks in the library. I will not have control over derived so I'd like to be sure that implementation
is tlX derived
.
Thank you for your time again.
The problem with doing what you are trying to do is cyclical dependencies. std::is_base_of
requires a complete type in order to work as far as I am aware.
Your code has TWO restrictions in tl1..
In the end, it ends up looking like:
tl1<T, D>
where D inherits tl1<T, D>
where D inherits tl1<T, D>
In other words, D will never be defined because Tl1 requires the definition of D as a template parameter but D must inherit from Tl1 which requires it.
Now if you remove the restriction on D, then the following code will compile as it should because the first restriction is met. However, if you uncomment the static_assert in tl1, it will NEVER compile because the definition of D depends on the definition of tl1 which depends on the definition of D and so on.. and so forth..
You'd get an error like:
invalid use of incomplete type 'class cl1'
struct is_base_of
^
note: forward declaration of 'class cl1'
Code:
#include <type_traits>
#include <list>
#include <string>
template <typename T, typename C>
class tl2 ;
template <typename D, typename T>
class tl1 {
private:
static_assert(std::is_base_of<tl2<T, D>, T>::value, "T should inherit from tl2");
//static_assert(std::is_base_of<tl1, D>::value, "D should inherit from tl1");
std::list<T> mTs ;
friend D ;
public:
tl1() {}
T & getTbyName() const ;
};
template <typename T, typename C>
class tl2 {
//static_assert(std::is_base_of<tl1<C, T>, C>::value, "D should inherit from Database");
public:
std::string getName() { return mName ; }
private:
//C & mC ;
std::string mName ;
};
class cl1;
class cl2 : public tl2<cl2, cl1> {
public:
cl2() {}
};
class cl1 : public tl1<cl1, cl2> {
public:
cl1() {}
};
int main() {
cl1 a;
cl2 b;
return 0;
}
If you replace std::is_base_of
with:
template<class B, class D>
struct is_base_of
{
template<typename T> struct dummy {};
struct Child : D, dummy<int> {};
static B* Check (B*);
template<class T> static char Check (dummy<T>*);
static const bool value = (sizeof(Check((Child*)0)) == sizeof(B*));
};
It will give you the error:
recursively required by substitution of 'template<class T> static char is_base_of<B, D>::Check(is_base_of<B, D>::dummy<T>*) [with T = <missing>]'
Which in my opinion is much clearer as to what is happening.
TLDR: You can't.