Class template where variable class derives from certain abstract class - c++

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.

Related

CRTP pattern with variable Base

Assume that one has two base classes Base1 and Base2 for which CRTP pattern is desired.
template <typename TDerived>
class Base1 {
};
template <typename TDerived>
class Base2 {
};
Now I would like to define a Derived class such that it can be "parametrized" with a base one.
What would be the proper way to define it in C++ (C++17 if that matters)?
Below is a pseudo-C++ code
template <template <typename> class TBase>
class Derived : public TBase<Derived<TBase>> {}; // Recursion problem here
In reality such a derived class is an extension that is applicable to any base class.
From your comment:
The problem I think still exists.
Consider your own pseudo-code when fed to a compiler (and some addition):
template <typename TDerived>
struct Base1 {
auto get() const -> int {
return static_cast<TDerived const*>(this)->a;
}
};
template <typename TDerived>
struct Base2 {
auto get() const -> int {
return static_cast<TDerived const*>(this)->b;
}
};
template <template<typename> typename TBase>
struct Derived : TBase<Derived<TBase>> {
int a;
int b;
};
auto main() -> int {
auto b = Derived<Base1>{};
b.a = 1;
b.b = 2;
return b.get();
}
Live example
As you can see, that pattern is no problem for the compiler.
Now I would like to define a Derived class such that it can be "parametrized" with a base one. What would be the proper way to define it in C++ (C++17 if that matters)?
The way you posted it in the question is the right way, and works all the way to C++98.
You seem to state that there's a recursion problem here, but there is not.
You have a template class Derived with a template template parameter Base1. The compiler now "knows" that this type Derived<Base1>. It is incomplete though, until the } is reached.
Then the compiler sees the base, which is TBase<something>, which is Base1 with some template parameter. Base1 need to be instantiated. The something is Derived<Base1>, which is an incomplete type.
The compiler then instantiate Base1 with Derived<Base1>. During that process, you cannot use Derived<Base1> in a way that it would require it to be complete.
Now that the base is instantiated and a complete type, the compiler finishes to instantiate Derived<Base1>, now complete.
There is no recursion here.

How to pass a templated function parameter with a subclass of the templated type in C++?

Compiling the following contrived example:
class Base
{};
class Derived : public Base
{};
template< typename T >
class A
{};
class B
{
public:
static void f( const A< Base >& ) {}
};
int main()
{
A< Base > tb;
A< Derived > td;
B::f( tb );
B::f( td );
return 0;
}
using g++-8 gives me the following error:
error: no matching function for call to 'B::f(A<Derived>&)'
B::f( td );
note: no known conversion for argument 1 from 'A<Derived>' to 'const A<Base>&'
Why?
Since Derived is-a Base and it doesn't override any of Base's stuff, why can't I give a Derived in the place of a Base in the templated function parameter?
It is true that Derived is derived from Base, but that doesn't mean that A<Derived> must therefore be derived from A<Base>. C++ templates don't work this way.
All that A<Derived> is, is a class, instantiated by the A template. You could've simply declared:
class A_Derived {
// ...
};
With the same members (if it had any), and pretty much got the same results. Same for A<Base>. With nothing else in the picture, the two classes have absolutely nothing to do with each other, whatsoever. You can draw a mental picture here, as if you made the following declarations:
class A_Derived {
};
and
class A_Base {
};
Which is pretty much what this is history. Do you see A_Derived being explicitly derived from A_Base here? Obviously not. If something expects a reference or a pointer to A_Base, you cannot give it A_Derived, because the two classes have absolutely nothing to do with each other. They are independent classes.
P.S. You could declare an explicit specialization of A<Derived> as being derived from A<Base>, if you so wish, but specialization is a completely different topic...
Template instances, like A<Base> and A<Derived>, are different types. In particular they do not have any inheritance relationship even if Base and Derived do.
There are quite a few ways you can make what you want work.
First, you could make A<Derived> explicitly derive from A<Base>, but that means adding a whole class definition.
template<>
class A<Derived> : public A<Base>
{};
Second, you can provide an implicit conversion from A<Derived> to A<Base> in the form of a constructor template. You can use std::enable_if and std::is_base_of to only allow A<T> where T is derived from Base, or directly std::is_same if you only want to consider this particular Derived type.
template<typename T>
class A
{
template<typename U, typename = std::enable_if_t<std::is_base_of_v<T, U>>>
A(A<U> const& other);
};
Third, you can provide an implicit conversion in the form of an operator template, in much the same way.
template<typename T>
class A
{
template<typename U, typename = std::enable_if_t<std::is_base_of_v<U, T>>>
operator U();
};
Fourth, you can make f a function template and restrict what types it takes.
template<typename T, typename = std::enable_if_t<std::is_base_of_v<Base, T>>>
static void f(A<T> const& a);

How to refer to a type defined in a derived class passed as a template argument?

Consider the following example:
template <typename T>
class A {
private:
typedef typename T::C C;
};
template <typename T>
class B : public A<B<T>> {
public:
typedef T C;
};
int main() {
B<int> b;
}
Compiling it with GCC gives the following error:
test.cc:5:23: error: no type named 'C' in 'B<int>'
typedef typename T::C C;
~~~~~~~~~~~~^
test.cc:9:18: note: in instantiation of template class 'A<B<int> >' requested here
class B : public A<B<T>> {
^
test.cc:15:10: note: in instantiation of template class 'B<int>' requested here
B<int> b;
^
Why does compiler give an error if B::C is defined and how to fix it?
At this point,
class B : public A<B<T>> {
… class B is incomplete. Class A can't look inside it.
The C type definition inside B is accessible from that point inside B, and on. It's also available inside function bodies in B because you can regard a function definition inside the class definition as a shorthand for placing it after the class. But an incomplete class contains nothing as viewed from outside: all that outside code can do is form pointers and references and use the class as template argument.
template< class C >
using Ungood = typename C::Number;
struct S
{
void foo() { Number x; (void) x; } // OK
Ungood<S> uhuh; //! Nyet.
using Number = double;
};
auto main() -> int {}
You can fix your code by changing the design. The most obvious is to pass the type as a separate template argument. But depending on what you're trying to achieve it may be that the inheritance you currently have, isn't really needed or even useful.
You can't because you're in a chicken-egg paradox. The definition of the base requires knowledge of the definition of the derived, which needs the definition of the base to complete. You simply have to come up with an alternative. One example would be to use an external metafunction to communicate the needed type to whoever needs it. Hopefully that's not in any part of the definition of the base's members or you're probably screwed.
Other alternative is to pass T as a second parameter.
You can't do that because of this:
A class is considered defined after the closing brace of its class-specifier has been seen [...]
And a few exceptions, none of which are valid in your case.
In other terms, you must consider your derived class as not fully defined when you try to use it in your base class to access the type C.
Anyway, you can exploit the fact that your derived class is a template class and do this:
template <typename T>
class A;
template <template<typename> class D, typename T>
class A<D<T>> {
private:
using C = T;
};
Aa you can see, I've not given a definition for the primary template class, thus only the specialization for template classes can be used.
Not sure this is the OP's real case, but it's the case in the example in the question.

c++ template specialization and derivation

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.

specializing on a subset of types in a C++ template

I have a question about template specialization in C++, and I am hoping someone here can help. I have a class that has 3 template parameters:
template<class A, class B, class C>
class myClass {
public:
void myFunc();
};
What I want to do is write several versions of myFunc that specialize on, say, type C, but are generic for types A and B. So I do NOT want the fully templated function like this:
template<class A, class B, class C>
void myClass<A, B, C>::myFunc()
{
// function code here
}
and I do NOT want a fully specialized function like this
void myClass<int, int, int>::myFunc()
{
// code goes here
}
Instead, I want to do something that would be similar to
template<class A, class B>
void myClass<A, B, int>::myFunc()
{
// code goes here
}
The idea is that if class type C is int, I would call one version of myFunc(), and if class type C is double, I would call a different version of myFunc. I've tried lots of difference combinations of template specialization syntaxes (too many to list here), and none seems to compile.
Could someone possibly point me in the right direction here? Thanks in advance for your help.
Michael
You can write a function template, and an overload, and delegate the work to it:
template<class A, class B, class C>
class myClass
{
//resolver doesn't need to define anything in it!
template<class> struct resolver {}; //empty, yet powerful!
public:
void myFunc()
{
doFun(resolver<C>());
}
//this is a function template
template<typename X>
void doFun(const resolver<X> & )
{
//this function will get executed when C is other than int
//so write your code here, for the general case
}
//this is an overload, not a specialization of the above function template!
void doFun(const resolver<int> & )
{
//this function will get executed when C = int
//so write your code here, for the special case when C = int
}
};
Note an important point : doFun(const resolve<int>& ) is an overloaded function, its not a specialization of the function template. You cannot specialize member function template without specializing the enclosing class template.
Read these articles:
Template Specialization and Overloading
Why Not Specialize Function Templates?
Dispatching on a resolver type as #Nawaz shows is IMHO the best way. Another option would be to move the real implementation of that function outside of the class, inside its own struct, make it static and partially specialize the struct. Inside the class, call that. Of course, if it accesses private parts of myClass, you need to make it friend:
template<class A, class B, class C>
class myClass;
template<class A, class B, class C>
struct myClassFuncs{
typedef myClass<A,B,C> class_type;
static void myFunc(class_type* self){
// generic for everything ...
}
};
template<class A, class B>
struct myClassFuncs<A,B,int>{
typedef myClass<A,B,int> class_type;
static void myFunc(class_type* self){
// specialized on C == int ...
}
};
// and so on ...
template<class A, class B, class C>
class myClass{
typedef myClassFuncs<A,B,C> func_holder;
friend class func_holder;
public:
void myFunc(){
func_holder::myFunc(this);
}
};
Though that leads to a lot of wrappers in the class and the specialized versions...
Another idea, which can be said to be pretty crazy, is to not have functions in the class but functors. Those get specialized and then called. This is more verbose, but allows a better access to which functions you want to specialize. Though, if they want to access private parts, you now need to make all of them friends. :/
template<class A, class B, class C>
class myClass;
template<class A, class B, class C>
class myClass_myFunc{
typedef myClass<A,B,C> class_type;
class_type* const _self;
public:
myClass_myFunc(class_type* self)
: _self(self)
{}
void operator() const{
// generic logic here
}
};
template<class A, class B>
class myClass_myFunc<A,B,int>{
typedef myClass<A,B,int> class_type;
class_type* const _self;
public:
myClass_myFunc(class_type* self)
: _self(self)
{}
void operator() const{
// specialized logic here
}
};
template<class A, class B, class C>
class myClass{
friend class myClass_myFunc<A,B,C>;
public:
myClass()
: myFunc(this)
{}
const myClass_myFunc<A,B,C> myFunc;
};