Is it possible to derive all template instantiations that have a derived class as their argument from the instantiation that has the base class as its argument?
In code:
class Base{};
class Derived1 : Base{};
class Derived2 : Base{};
template<typename T>
class Templ /*: Templ<Base> if T derives from Base*/
{};
How would one do that?
Make a specialization for Templ<Base>, and then use SFINAE along with std::is_base_of to derive a separate specialization from Templ<Base>.
template<typename T, typename V = void>
class Templ
{};
template<>
class Templ<Base>
{};
template<bool B, typename R = void>
using enable_if_t = typename std::enable_if<B, R>::type;
template<typename T>
class Templ<T, enable_if_t<std::is_base_of<Base, T>::value>>
: public Templ<Base>
{};
It depends what exactly you want to do. If you want this to work only for some specific, known baseclass, it can easily accomplished, e.g. like in 0x499602D2's answer.
However the way I interpret your question you want to have a template which derives from the instantiation for it's arguments baseclass, whichever that might be. This is not possible in standard c++ (yet), since there is no way to query what class a specific type is derived from, only if it is derived from a specific classes. For more on this (and possible future solutions look at this question.
Related
Given a list of classes, I need to find the inheritance relationships between the classes. For example:
class Animal {};
class Dog : public Animal {};
class Bulldog : public Dog {};
class Cat : public Animal {};
using boost::mp11::mp_list;
template<typename... Class>
using class_bases = ...; // a mp_list of mp_list<Derived, Base>, with void meaning no base
static_assert(
std::is_same_v<
class_bases<Animal, Dog, Bulldog, Cat>,
mp_list<
mp_list<Animal, void>,
mp_list<Dog, Animal>,
mp_list<Bulldog, Dog>,
mp_list<Cat, Animal>
>
>);
I have a solution that works well for single inheritance hierarchies. It is O(n) and it does not use recursion:
template<typename Derived, typename Class>
struct direct_base_impl {
static Class select(Class*);
};
template<typename Derived>
struct direct_base_impl<Derived, Derived> {
static void select(...);
};
template<typename Derived, typename... Class>
struct direct_base : direct_base_impl<Derived, Class>... {
using direct_base_impl<Derived, Class>::select...;
using type = decltype(select(std::declval<Derived*>()));
};
static_assert(
std::is_same_v<
direct_base<Bulldog, Animal, Dog, Bulldog>::type,
Dog
>);
template<typename... Class>
using class_bases = mp_list<
mp_list<
Class,
typename direct_base<Class, Class...>::type
>...
>;
Unfortunately this approach won't work in presence of multiple inheritance.
I have coded a solution that uses brute force. It works, except for classes that inherit the same base both directly and indirectly. I don't care about this case, because, in my context (yomm2 open multi-methods library), it doesn't make sense anyway. More annoying, that solution has a O(n^3) worst case "performance", in presence of MI.
Does anybody know of a solution to this problem, or has ideas?
There are some additional SFINAE-based gesticulations for dealing with multiple inheritance, in this situations.
Fortunately, you don't need to do them yourself, because std::is_base_of has already done them for you:
std::is_base_of<A, B>::value is true even if A is a private, protected,
or ambiguous base class of B.
Emphasis mine. Simply reimplement your template to use std::is_base_of or std::is_base_of_v and it'll deal with multiple inheritance on your behalf.
I have a non-template parent interface and am trying to use SFINAE on a child class. All I want to do is verify the type of the first template parameter can be constructed without any arguments. My issue is in forward declaration. Based on my understanding, SFINAE requires a class to be forward declared and then specialized. This is currently what I'm trying:
class ParentInterface
{};
template<class, class = void>
class Child : public ParentInterface; // <-- This semi-colon is the error
template<class Ty>
class Child<Ty, std::enable_if_t<std::is_constructible_v<Ty>>>
: public ParentInterface
{};
The answers I was able to find related to this had to do with inheriting from a SFINAE class. What do I need to do to get my intended functionality?
template<class, class = void>
class Child : public ParentInterface;
is neither a declaration nor definition.
You probably want declaration:
`template<class, class = void>
class Child;
And then you can add your partial specialization definition:
template<class Ty>
class Child<Ty, std::enable_if_t<std::is_constructible_v<Ty>>>
: public ParentInterface
{};
When using template like this:
class A {…}
class B : A {…}
class C : A {…}
template<typename T>
class D{…}
I need T can only be B or C. Which means T must be a derivation of A.
Is there any way to do this? Thanks!
Use std::is_base_of along with std::enable_if:
template<typename T, typename X = std::enable_if<std::is_base_of<A, T>::value>::type>
class D{...}
Note that it will accept any T as long as it derives from A. If you need T to be either B or C, then you need to modify it, and use std::is_same or/and std::conditional along with std::enable_if.
You could make it clean as:
template<typename T, typename Unused = extends<T,A>>
class D{...}
where extends is defined as:
template<typename D, typename B>
using extends = typename std::enable_if<std::is_base_of<B,D>::value>::type;
static_assert can also be used (like other answers have shown) if you want it to result in error and compilation failure. However if you need selection or deselection, say from many specializations, then use the above approach.
Hope that helps.
You can use static_assert in combination with std::is_base_of:
#include <type_traits>
class A {};
class B : A {};
class C : A {};
class X{};
template<typename T>
class D
{
static_assert(std::is_base_of<A,T>::value, "T must be derived from A");
};
int main()
{
D<C> d_valid;
D<X> d_fails; // compilation fails
return 0;
}
live on ideone
Yes, this should do it:
template<typename T>
class D {
static_assert(std::is_base_of<A,T>::value, "not derived from A");
// ...
};
Demo here.
But this is not the idea behind templates. If you write templated code, then it should be generic, I.e. work for all types that support the operations that you apply on them.
In other words: Is it possible to make a template specialisation that inherits from its base, like this:
template <class T>
class A{};
template <>
class A<int>:public A<>{};
so that A has all of A's functions?
I'm new here, so I dunno how to format, just in case the code comes up incorrectly.
You can, with a bit of trickery. This pattern is sometimes called “template subclassing” and is used extensively in the SeqAn library.
The trick is to give the base class an additional template argument tag which determines the type identity:
template <typename T, typename Spec = void>
struct A { … };
// inheritance tag:
struct Derived { };
template <typename T>
struct A<T, Derived> : public A<T, void> { … };
Here, void denotes the base (you could also use a dedicated tag Base but void works fine) and Derived, an empty struct, denotes the derived class.
Now you can instantiate and use the templates as follows:
A<int> the_base;
A<int, Derived> the_derived;
the_base.do_something();
the_derived.do_something();
For a real-world example, consider the String class from SeqAn:
String<Dna> some_dna = "GATTACA";
String<Dna, Packed> more_dna = "GATTACA";
The second type derived from the first one, but is a specialisation which packs its characters as tightly as possible (for DNA, this means putting four DNA characters in each byte).
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.