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.
Related
Given the following classes:
// Some random class
class A { };
// A templated class with a using value in it.
template<class TYPE_B>
class B {
public:
using TYPE = TYPE_B;
};
Next we use these two classes in class C. But if we are using B as the template parameter we would like to obtain the TYPE defined in it.
template<class TYPE_C>
class C {
// A check to see if we have a class of type B
static constexpr bool IS_B = std::is_same<B<int32_t>, TYPE_C>::value ||
std::is_same<B<int64_t>, TYPE_C>::value;
public:
// This is what not works. How to get B::TYPE here?
using TYPE = std::conditional<IS_B, TYPE_C::TYPE, TYPE_C>;
};
Class C would we used like:
C<A> ca;
C<B<int32_t>> cb32;
C<B<int64_t>> cb64;
I am compiling this in GCC. My fear what I would like not have to do is to use the std::is_same statement for each type used with B. Put that in the std::conditional. Are there any alternatives?
You have two issues in your code:
You are missing a typename before TYPE_C::TYPE. Since TYPE_C::TYPE is a dependent name, you need to use typename to tell the compiler that you are looking for a type.
You cannot use TYPE_C::TYPE ins the std::conditional1 expression because when TYPE_C is not B<>, that expression is invalid, but will still be evaluated.
One simple solution is to use an intermediate template to access the type, using template specialization, e.g.
template <class T>
struct get_C_type {
using type = T;
};
template <class T>
struct get_C_type<B<T>> {
using type = T;
};
template<class TYPE_C>
class C {
public:
// you still need a typename here
using TYPE = typename get_C_type<TYPE_C>::type;
};
1 You probably want to use std::conditional_t or std::conditional<>::type here.
I would like to define a class which inherits from a bunch of classes but which does not hide some specific methods from those classes.
Imagine the following code:
template<typename... Bases>
class SomeClass : public Bases...
{
public:
using Bases::DoSomething...;
void DoSomething(){
//this is just another overload
}
};
The problem is now if just one class does not have a member with the name DoSomething I get an error.
What I already tried was emulating an "ignore-if-not-defined-using" with a macro and SFINAE but to handle all cases this becomes very big and ugly!
Do you have any idea to solve this?
It would be really nice if I could define: "Hey using - ignore missing members".
Here I have some sample code: Godbolt
The problem with Jarod42's approach is that you change what overload resolution looks like - once you make everything a template, then everything is an exact match and you can no longer differentiate between multiple viable candidates:
struct A { void DoSomething(int); };
struct B { void DoSomething(double); };
SomeClass<A, B>().DoSomething(42); // error ambiguous
The only way to preserve overload resolution is to use inheritance.
The key there is to finish what ecatmur started. But what does HasDoSomething look like? The approach in the link only works if there is a single, non-overloaded, non-template. But we can do better. We can use the same mechanism to detect if DoSomething exists that is the one that requires the using to begin with: names from different scopes don't overload.
So, we introduce a new base class which has a DoSomething that will never be for real chosen - and we do that by making our own explicit tag type that we're the only ones that will ever construct. For lack of a better name, I'll name it after my dog, who is a Westie:
struct westie_tag { explicit westie_tag() = default; };
inline constexpr westie_tag westie{};
template <typename T> struct Fallback { void DoSomething(westie_tag, ...); };
And make it variadic for good measure, just to make it least. But doesn't really matter. Now, if we introduce a new type, like:
template <typename T> struct Hybrid : Fallback<T>, T { };
Then we can invoke DoSomething() on the hybrid precisely when T does not have a DoSomething overload - of any kind. That's:
template <typename T, typename=void>
struct HasDoSomething : std::true_type { };
template <typename T>
struct HasDoSomething<T, std::void_t<decltype(std::declval<Hybrid<T>>().DoSomething(westie))>>
: std::false_type
{ };
Note that usually in these traits, the primary is false and the specialization is true - that's reversed here. The key difference between this answer and ecatmur's is that the fallback's overload must still be invocable somehow - and use that ability to check it - it's just that it's not going to be actually invocable for any type the user will actually use.
Checking this way allows us to correctly detect that:
struct C {
void DoSomething(int);
void DoSomething(int, int);
};
does indeed satisfy HasDoSomething.
And then we use the same method that ecatmur showed:
template <typename T>
using pick_base = std::conditional_t<
HasDoSomething<T>::value,
T,
Fallback<T>>;
template<typename... Bases>
class SomeClass : public Fallback<Bases>..., public Bases...
{
public:
using pick_base<Bases>::DoSomething...;
void DoSomething();
};
And this works regardless of what all the Bases's DoSomething overloads look like, and correctly performs overload resolution in the first case I mentioned.
Demo
How about conditionally using a fallback?
Create non-callable implementations of each method:
template<class>
struct Fallback {
template<class..., class> void DoSomething();
};
Inherit from Fallback once for each base class:
class SomeClass : private Fallback<Bases>..., public Bases...
Then pull in each method conditionally either from the base class or its respective fallback:
using std::conditional_t<HasDoSomething<Bases>::value, Bases, Fallback<Bases>>::DoSomething...;
Example.
You might add wrapper which handles basic cases by forwarding instead of using:
template <typename T>
struct Wrapper : T
{
template <typename ... Ts, typename Base = T>
auto DoSomething(Ts&&... args) const
-> decltype(Base::DoSomething(std::forward<Ts>(args)...))
{
return Base::DoSomething(std::forward<Ts>(args)...);
}
template <typename ... Ts, typename Base = T>
auto DoSomething(Ts&&... args)
-> decltype(Base::DoSomething(std::forward<Ts>(args)...))
{
return Base::DoSomething(std::forward<Ts>(args)...);
}
// You might fix missing noexcept specification
// You might add missing combination volatile/reference/C-elipsis version.
// And also special template versions with non deducible template parameter...
};
template <typename... Bases>
class SomeClass : public Wrapper<Bases>...
{
public:
using Wrapper<Bases>::DoSomething...; // All wrappers have those methods,
// even if SFINAEd
void DoSomething(){ /*..*/ }
};
Demo
As Barry noted, there are other drawbacks as overload resolution has changed, making some call ambiguous...
Note: I proposed that solution as I didn't know how to create a correct traits to detect DoSomething presence in all cases (overloads are mainly the problem).
Barry solved that, so you have better alternative.
You can implement this without extra base classes so long as you’re willing to use an alias template to name your class. The trick is to separate the template arguments into two packs based on a predicate:
#include<type_traits>
template<class,class> struct cons; // not defined
template<class ...TT> struct pack; // not defined
namespace detail {
template<template<class> class,class,class,class>
struct sift;
template<template<class> class P,class ...TT,class ...FF>
struct sift<P,pack<>,pack<TT...>,pack<FF...>>
{using type=cons<pack<TT...>,pack<FF...>>;};
template<template<class> class P,class I,class ...II,
class ...TT,class ...FF>
struct sift<P,pack<I,II...>,pack<TT...>,pack<FF...>> :
sift<P,pack<II...>,
std::conditional_t<P<I>::value,pack<TT...,I>,pack<TT...>>,
std::conditional_t<P<I>::value,pack<FF...>,pack<FF...,I>>> {};
template<class,class=void> struct has_something : std::false_type {};
template<class T>
struct has_something<T,decltype(void(&T::DoSomething))> :
std::true_type {};
}
template<template<class> class P,class ...TT>
using sift_t=typename detail::sift<P,pack<TT...>,pack<>,pack<>>::type;
Then decompose the result and inherit from the individual classes:
template<class> struct C;
template<class ...MM,class ...OO> // have Method, Others
struct C<cons<pack<MM...>,pack<OO...>>> : MM...,OO... {
using MM::DoSomething...;
void DoSomething();
};
template<class T> using has_something=detail::has_something<T>;
template<class ...TT> using C_for=C<sift_t<has_something,TT...>>;
Note that the has_something here supports only non-overloaded methods (per base class) for simplicity; see Barry’s answer for the generalization of that.
I want to ensure that in the definition of the following templated class B, that the class A derives from an abstract class C. Can I do this?
template <class A>
class B {
// A must derive from C
...
};
I am using C++11.
Use std::is_base_of:
template <class A>
class B {
static_assert(std::is_base_of<C, A>::value
, "A must derive from C");
//...
};
Note that is_base_of<C, C>::value is true, so you may want to also use std::is_same to ensure A is not actually C itself:
static_assert(std::is_base_of<C, A>::value && !std::is_same<C, A>::value
, "A must derive from C");
Overall this is a SFINAE problem.
In C++11 there are better ways, but if you're using C++03, you could try something like this:
template <class A>
class B {
public:
B() { dummy((A*)0); }
private:
void dummy(C *test) {}
};
That is, add dummy function taking a pointer of type C. Then call it from your constructor(s) with a value of type A*. This cannot compile for types where A doesn't derive from C.
I'd like to place a POD type constrain on type parameter T of class template A and then derive another class template B from the satisfactory A. Besides, B is supposed to have different implementation according to constancy of instance of A. The purpose of doing all this is about, well you know, for better type checking before runtime.
All I can figure out is a tentative definition of A
template <typename T, typename POD=void>
class A;
template <typename T>
class A <T, std::enable_if<std::is_pod<T>::value>::type>
{
//blah...
};
so that A can't be instantialized when passing non-POD type, as you might have noticed that partial parameterization does the trick like a type switch.
But I can't figure out how B could be defined. I presume it looks like the following
template <typename A?>
class B;
template <>
B<const A?> : public A?
{
//blah...
};
template <>
B<A?> : public A?
{
//blah...
};
Any brilliant idea?
PS: Personally I tend to be highly critical. But just post how you think this could be done anyway.
There is no brilliant idea if the specializations are going to be completely different. You have to go with this:
template <typename T>
class B;
template <typename T>
class B<const A<T>> : public A<T>
{
};
template <typename T>
class B<A<T>> : public A<T>
{
};
which is almost same as you've written yourself except ? symbol.
You can instantiate this class as:
B<A<int>> x; //it chooses the second specialization
B<const A<int>> y; //it chooses the first specialization
See online demo. Note that you've forgotten typename here:
typename std::enable_if<std::is_pod<T>::value>::type
I fixed that too.
If some code in the specializations are going to be same, then you could do some trick in order to share the common part, but I cannot suggest anything as I don't know what you're going to put in the specializations.
Can I specify exactly what kind of arguments a template can receive? For example, I'd like to create a template that can only be instantiated with classes that are or extend class A. In Java, generics support this with:
class B<T extends A> { }
Can something similar be achieved with templates in C++?
template <typename T (?)> class B { }
There are two ways to do this.
First, through a hidden dummy template parameter that uses std::enable_if with a std::is_base_of<A, T>::value as condition. If the latter expression evaulates to false, then the nested type does not exist in std::enable_if. If you were using this on overloaded functions, SFINAE then means "substitution failure is not an error", and the overload in question would be removed from the set of viable functions. HOwever in this situation, there is no other class template to match your call, and then you do get a compile-time error.
SFINAE is a very subtle mechanism and easy to get wrong. E.g. if you have multiple class specializations with different SFINAE conditions, you have to make sure that they are all non-overlapping, or else you get an ambiguity.
Second, you can do a simple static_assert with a std::is_base_of<A,T>::value inside the body of the class. The advantage of this method is that you also specify a more readable error message compared to the SFINAE method. A disadvantage is that you always get an error, and you cannot silently suppress this particular template and select another one. But overall I think this method is recommended in your case.
#include<type_traits>
class A {};
class C: public A {};
class D {};
// first alternative: SFINAE on hidden template parameter
template
<
typename T,
typename /* dummy */ = typename std::enable_if<
std::is_base_of<A, T>::value
>::type
>
class B
{
};
// second alternative: static_assert inside class
template
<
typename T
>
class E
{
static_assert(std::is_base_of<A, T>::value, "A should be a base of T");
};
int main()
{
B<A> b1;
B<C> c1;
//B<D> d1; // uncomment this line to get a compile-time error
E<A> b2;
E<C> c2;
//E<D> d2; // uncomment this line to get a compile-time error
return 0;
}
As was pointed out in the comments, you can use either a decent C++11 compiler (VC++ 2010 or later, gcc 4.5 or later) or the Boost or TR1 libraries to get the <type_traits> functionality. Note however that the std::is_base_of<A, A>::value evaluates to true, but the old boost::is_base_of<A, A>::value used to evalute to false.
You can do this with static_assert and is_base_of:
#include <type_traits>
template<typename T> class D {
static_assert(std::is_base_of<A, T>::value, "must be derived from A");
};
Or you can use enable_if:
#include <type_traits>
template<typename T, typename = void> class D;
template<typename T> class D<T, typename std::enable_if<std::is_base_of<A, T>::value>::type> {
};
For C++03 you can use boost; is_base_of from Boost.TypeTraits, static_assert from Boost.StaticAssert, enable_if from Boost.EnableIf.