Consider something like this in C#:
class C<T> {}
class D : C<E> {}
class E : C<D> {}
Is an equivalent construction possible in C++ using templates?
Yes, you can forward declare E:
template <typename T> class C {};
class E;
class D : public C<E> {};
class E : public C<D> {};
or, as per Franks suggestion:
template <typename T> class C {};
class D : public C<class E> {};
class E : public C<D> {};
Whether this works in your real case depends on whether C requires T to be complete (it does not in this stripped down example).
PS: I don't know C#, so I am not sure if you wanted private or public inheritance. The above uses public inheritance, while the default for classes declared with the keyword class is private inheritance.
Related
Often in derived template classes I need to refer to the base to access members. I end up writing code like this:
template<typename A>
struct BaseClass
{
};
template<typename B>
struct Derived : public BaseClass<int>
{
using Base = BaseClass<int>;
};
This gets more verbose and harder to maintain for a large number of classes with a lot of template arguments.
Is there a cleaner way to import base symbols in this case?
I think you can do things the other way i.e. defer the base resolution to the base class instead, so that it would be automatically resolved for any new derived class without bothering of rewriting it for each one.
Something like:
template <typename A>
struct BaseClass
{
using Base = BaseClass<A>;
};
template <typename B>
struct Derived : public BaseClass<int>
{};
Live example
If Derived is not itself a template class: You can simply use BaseClass (the inherited injected-class-name):
struct Derived : public BaseClass<int>
{
void f()
{
BaseClass::f();
}
};
If it is also a template, using Base = BaseClass<int>; is probably the best way.
Consider the following code :
template<class C, class P>
//class Cchild : public C::NestedClass // Works
class Cchild : public C::NestedTemplateClass<P> // Fails : how to inherit from nested template class defined in C ?
{
};
Compiler compiles fine when template class Cchild inherits from a nested class C::NestedClass . However, it fails to compile if I want Cchild to inherit from a nested template class C::NestedTemplateClass<P>
How can I do this ?
The syntax is:
template<class C, class P>
class Cchild : public C::template NestedTemplateClass<P>
{
};
The error message from gcc was actually quite readable:
t.C:3:26: error: non-template ‘NestedTemplateClass’ used as template
class Cchild : public C::NestedTemplateClass<P>
^~~~~~~~~~~~~~~~~~~
t.C:3:26: note: use ‘C::template NestedTemplateClass’ to indicate that it is a template
The title almost says everything: Is there a way in C++ to get a class's base type(s) at compile time? I. e. is it possible to hand a class to a template, and let the template use other templates to which it hands the bases of the given class?
My question is not whether I can implement such a functionality myself, there is no question I can (using traits and the like). My question is whether there is some (obscure) builtin functionality that could be used to this end.
gcc supports this. See
Kerrek's answer
tr2/type_traits
Andy Prowl's code example
n2965
What is the status of N2965 - std::bases and std::direct_bases?
How to query for all base classes of a class at compile time?
n2965 provides an example.
This simple examples illustrates the results of these type traits. In
the Suppose we have the following class hierarchy:
class E {};
class D {};
class C : virtual public D, private E {};
class B : virtual public D, public E {};
class A : public B, public C {};
It follows that bases<A>::type is tuple<D, B, E, C, E>
Similarly, direct_bases<A>::type is tuple<B, C>
Andy Prowl's code example is as follows:
#include <tr2/type_traits>
#include <tuple>
template<typename T>
struct dbc_as_tuple { };
template<typename... Ts>
struct dbc_as_tuple<std::tr2::__reflection_typelist<Ts...>>
{
typedef std::tuple<Ts...> type;
};
struct A {};
struct B {};
struct C : A, B {};
int main()
{
using namespace std;
using direct_base_classes = dbc_as_tuple<tr2::direct_bases<C>::type>::type;
using first = tuple_element<0, direct_base_classes>::type;
using second = tuple_element<1, direct_base_classes>::type;
static_assert(is_same<first, A>::value, "Error!"); // Will not fire
static_assert(is_same<second, B>::value, "Error!"); // Will not fire
}
Seemed like a good strategy to compose my objects like this (as policies):
template<typename FluxType, typename SourceType>
class Model : public FluxType, public SourceType
{ };
//later in the code:
template<typename FluxType, typename SourceType>
class ConcreteModel : public Model<FluxType, SourceType>
{};
However, FluxType and SourceType are classes that use the same data. So I had used virtual inheritance:
class ConcreteModelProps{};
class ConcreteFlux : virtual public ConcreteModelProps
{};
class ConcreteFlux2 : virtual public ConcreteModelProps
{/*sligthly different implementation*/};
class ConcreteSource : virtual public ConcreteModelProps
{};
class DefaultSource2
{/*no need for data*/};
That way I could compose my ConcreteModel with different FluxType and SourceType objects.
ConcreteModel<ConcreteFlux, DefaultSource2> /*or whatever*/.
The fact is that the the data that are defined in ConcreteModelProps are closely related to ConcreteModel. It seems to me that I'm doing at least something wrong. How can I make this design better? Preferably without the virtual inheritance?
thx, dodol
Well, it's simple: you are violating the LISKOV Substitution Principle by having ConcreteFlux inherit from ConcreteModelProps; so it's only right you pay the price.
Now, if you externalized the data, you could be working with a saner model.
template <typename FluxType, typename SourceType>
class Model {
public:
typedef typename FluxType::DataType DataType;
}; // class Model
template <typename M>
class ConcreteModel: public M {
}; // class ConcreteModel
And then:
class ConcreteFlux {
public:
typedef ConcreteModelProps DataType;
};
class ConcreteSource {
public:
typedef ConcreteModelProps DataType;
};
template <typename Data>
class DefaultSource {
typedef Data DataType;
};
With finally:
class ConcreteModel<Model<ConcreteFlux, ConcreteSource>> {};
Of course, this means that now all methods of ConcreteFlux and ConcreteSource need be passed the handle to ConcreteModelProps in each of their method. That's what externalization was about.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Is there a way to prevent a class from being derived from twice using a static assert and type trait?
What I'd like to prevent is more than one of the C based template from being derived in D (i.e. there should only ever be one instance of C derived from). Was hoping for maybe a static assert in C or B that may solve this.
// My Classes
template <class T>
class A {};
class B {};
template <class T, class S>
class C : public B, public virtual A<T> {};
// Someone elses code using my classes
class D : public C<Type1, Type2>, public C<Type3, Type4>
{
};
As it stands, it's impossible for B or C to detect what else a more derived class inherits from, so you can't add an assertion there. However, by adding a "curiously recursive" template parameter, you can tell C what the derived class is. Unfortunately, this does require the derived class to give the correct template argument, and there's no way to enforce that.
You can then determine whether the derived class inherits from B in more than one way; it is a base class, but you can't convert a derived class pointer to B* (since that conversion is ambiguous). Note that this doesn't necessarily indicate multiple inheritance; the test will also fail if there's non-public inheritance.
So the best solution I can think of is:
#include <type_traits>
template <class T> class A {};
class B {};
template <class T, class S, class D>
class C : public B, public virtual A<T> {
public:
C() {
static_assert(
std::is_base_of<C,D>::value && std::is_convertible<D*,B*>::value,
"Multiple inheritance of C");
}
};
struct Type1 {};
struct Type2 {};
struct Type3 {};
struct Type4 {};
class Good : public C<Type1, Type2, Good> {};
class Evil : public C<Type1, Type2, Evil>, public C<Type3, Type4, Evil> {};
int main()
{
Good good;
Evil evil; // Causes assertion failure
}
I had to put the assertion in the constructor rather than the class definition, since some of the types are incomplete when the class template is instantiated. Unfortunately, this means that the error will only be reported for classes that are actually instantiated.