Can you template specialize a subclass that is not templated? - c++

Here is my situation:
Base class, no templated type:
struct Thing
{
} ;
Templated class, extends that very base class
template <typename T> struct VertexWriter : public Thing
{
template <typename S>
bool intersects( S* otherThing )
{
// has a body, returns T or F
}
} ;
Derived class, CONCRETE type (no template)
struct Rocket : VertexWriter<VertexPNCT>
{
template <typename S>
bool intersects( S* otherThing ) ; // WANTS TO OVERRIDE
// implementation in VertexWriter<T>
} ;
But template typename<S> bool VertexWriter<T>::intersects cannot be marked virtual, because it is a template class.
There are many classes that derive from the VertexWriter<VertexPNCT> specialization, so template specializing VertexWriter<VertexPNCT> would not work.
So the normal thing to do is to provide a template specialization.
But Rocket specifies it is a VertexWriter<VertexPNCT>, so it is no longer a template class. Can it specialize OR override intersects as if it were a virtual function?

No, as you've stated you cannot use virtual functions, which would provide runtime polymorphism.
That said, depending on what leeway you have on changing the layout of your classes, you might be able to do something using CRTP.
template <typename T, typename Derived> struct VertexWriter : public Thing
{
template <typename S>
bool intersects( S* otherThing )
{
return static_cast<Derived*>(this)->insersects_impl(otherThing);
}
template<typename S>
bool insersects_impl( S* otherThing)
{
// Whatever
}
} ;
struct Rocket : VertexWriter<VertexPNCT, Rocket>
{
template <typename S>
bool intersects_impl( S* otherThing ) { ... } // WANTS TO OVERRIDE
// implementation in VertexWriter<T>
} ;
The base implementation of intersects simply forwards to the CRTP function. If the derived class overrides it, it'll use the override, but otherwise it'll fall back the default. Note, this does complicate your class hierarchy, but might accomplish what you're looking for.

No, you cannot.
Templated member functions cannot be virtual.
It doesn't matter whether VertexWriter is templated, specialized, or a normal class.

You could template VertexWriter on S and make intersects a virtual function of that class template
template <typename T, typename S> struct VertexWriter : public Thing
{
virtual bool intersects( S* otherThing )
{
// has a body, returns T or F
}
} ;
Now you can override intersects in a derived class
template<typename S>
struct Rocket : VertexWriter<VertexPNCT, S>
{
virtual bool intersects( S* otherThing ) ; // WANTS TO OVERRIDE
// implementation in VertexWriter<T>
}

Related

Class specialization involving CRTP and inner type

I would like to build the following classes. Base class is defining functions to be implemented, Derived implements this interface.
template <class T, class V>
class IBase
{
public:
virtual void foo(const typename V::t_args&) =0;
};
template<class T>
struct T_args
{
T z;
};
class Derived : public IBase<double, Derived>
{
public:
typedef T_args<double> t_args;
Derived() {}
void foo(const t_args& x)
{ /* do some stuff */ }
};
Compiler is complaining about Derived as an imcomplete type; I can't understand the reason why.
Is there any mean to get this class structure right?
I'm forced to code with c++98, but I'm interested for any solution in c++11 and above.
In your base template class:
virtual void foo(const typename V::t_args&) =0;
This is referencing some inner class or type called t_args of its V template parameter. When referencing a class member, the class's definition must be complete (in order to figure out what t_args is). You are attempting to use this template class as follows:
class Derived : public IBase<double, Derived>
You're passing in Derived for your V, however its class definition is incomplete. If the template base class only referenced its V parameter, it is generally "ok". However your template requires its template parameter type to be complete, because it needs to know what the heck that t_args is, and your derived class is not complete until it's fully defined. But it cannot be fully defined until its base class is fully defined. Sort of like a chicken vs egg situation.
There is no turnkey solution to this kind of a circular reference, of sorts. The only thing that can be done is restructure the class, so your "argument" type is an independent class, rather than the derived class.
Another workaround is to use some traits class:
// The traits class
template <typename T> struct Arg;
template <class T, class V>
class IBase
{
public:
virtual ~IBase() {}
virtual void foo(const typename Arg<V>::t_args&) = 0; // V can be incomplete here
// but Arg<V> should be complete
};
// So go to define Arg<Derived>:
// Result class
template<class T>
struct T_args
{
T z;
};
// Forward declaration, Arg<V> accept incomplete type
class Derived;
// Specialization for Derived
// should not use internal of Derived as it is incomplete
template <>
struct Arg<Derived>
{
typedef T_args<double> t_args;
};
// Now definition of Derived
class Derived : public IBase<double, Derived>
{
public:
typedef Arg<Derived>::t_args t_args; // Should probably go in IBase for ease usage
Derived() {}
void foo(const t_args& x) /* override */
{ /* do some stuff */ }
};
Demo
After reading the explanation by Sam Varshavchik, here is a potential workaround of my problem by adding the t_args class in the template signature of the base class:
template <class V, class Args>
class IBase
{
public:
typedef Args t_args;
virtual void foo(const Args&) =0;
};
template<class T>
struct T_args
{
T z;
};
template <class T>
class Derived : public IBase<Derived<T>, T_args<T> >
{
public:
typedef typename Derived::IBase::t_args t_args;
Derived() {}
void foo(const t_args&)
{ /* do some stuff */ }
};

optional virtual function in template hierarchy depending on parameter

I have a template hierarchy, and I want it to have clone() function depending on whether template type is copy-constructible. As a first step I want to begin with additional parameter bool Clonable:
template<class T, bool Clonable>
class Base {
T t;
void foo();
virtual void bar();
virtual unique_ptr<Base> clone() const = 0; //should be only for Clonable=true
};
template<class T, bool Clonable>
class Derived : public Base<T, Clonable> {
virtual void bar() override;
virtual unique_ptr<Base> clone() const override; ////should be only for Clonable=true
};
Unfortunately, instantiation of virtual functions does not depend on whether they are called or not. So I suppose that I should go with partial specialization. However, straightforward way leads to very much of code duplication. Could anyone recommend the way to achieve this with minimum code duplication?
Unfortunately, contrary to a few of the comments here, SFINAE cannot help you here. That's because a non-template member of a template class is not considered a template, and therefore cannot be SFINAE'ed out: http://coliru.stacked-crooked.com/a/258e20a0293d93f0. The standard approach to solve this would typically to make it a template in a trivial way:
template <class U = T, std::enable_if ... >
virtual std::unique_ptr<Base> clone() const = 0;
But virtual functions can't be templates, so this doesn't work.
The way to avoid repetition in this case is to inherit from a class that conditionally has the member:
template <class Base, bool Cloneable>
struct CloneInterface;
template <class Base>
struct CloneInterface<Base, false> {};
template <class Base>
struct CloneInterface<Base, true> {
virtual unique_ptr<Base> clone() const = 0;
}
And now you just inherit:
template<class T, bool Clonable>
class Base : CloneInterface<Base<T, Clonable>, Clonable> {
T t;
void foo();
virtual void bar();
};
Notice that we inherit from a base class that is templated on the derived (the derived class in question is called Base, to make things more confusing :-) ). This technique is called CRTP and it is quite powerful as it can inject interface and implementations into classes, and as you can see can do so conditionally as well.
To get the implementation, we use CRTP again:
template <class T, bool Clonable, class D>
struct BaseHelper;
template <class T, class D>
struct BaseHelper<T, false, D> : Base<T, false> {};
template <class T, class D>
struct BaseHelper<T, true, D> : Base<T, true> {
unique_ptr<Base<T, true>> clone() override { return make_unique<D>(static_cast<D&>(*this)); }
};
template<class T, bool Clonable>
class Derived : public BaseHelper<T, Clonable, Derived<T, Clonable>> {
virtual void bar() override;
};

Is it possible for a specialized version to share some functionalities with the original template class?

Is it possible for a specialized version of a class to share some or all functionalities of the original template class?
i.e. consider there is a template class,
template <typename T>
class A
{
A()
{}
A(const A& ref)
{}
void f1()
{
//do something
}
void f2()
{
//do something
}
void f3()
{
//do something
}
}
and it has a specialized version for a specific datatype, which only intend to add some addition functionalities to the generic version in addition the original generic functionalities.
template<>
class A<int>
{
void f4()
{
//do something
}
}
now what I specifically want is that this specialized version to be sharing everything from its generic version including the constructors if possible.
It is usually possible to implement that by restructuring the class hierarchy:
template <typename T>
class A_base
{
// All the f1() functions, et. al, implemented here
};
template<typename T> class A : public A_base<T> {
public:
// An empty shell of a class, with the constructor
// forwarding its arguments to the superclass.
template<typename ...Args> A(Args && ...args)
: A_base(std::forward<Args>(args)...)
{
}
};
template<>
class A<int> : public A_base<int>
{
// Same constructor.
void f4()
{
//do something
}
};
You end up moving all class methods, class members, into a base class, with your template class consisting of nothing more than deriving from the base class template; and an empty facade otherwise.
Then, your specialization derives from the base class the same way, and adds its own methods.
Another alternative is to implement this kind of derivation "backwards".
// Empty template class.
template<typename T> class A_extra {};
// Your specialization, with the extra method:
template<>
class A_extra<int> {
void f4()
{
}
};
// And the template class inherits from it:
template<typename T> class A : public A_extra<T> {
// Your template class
};
Depending on the particular details of your template class, one or the other approach should work; or some variation on the same theme.

Calling a templated method allowing only subclasses as parameter

Suppose I have set of classes inheriting from a single superclass S:
class S{ ... };
class C1 : public S{ ... };
class C2 : public S{ ... };
Then suppose I have a templated method:
template<class T> void foo(T* instance);
I would like to statically check that foo is never called providing an instance of the superclass but only called providing one of the (concrete) subclasses (e.g. explicitly calling foo<C1>(x) for instance)
Is this possible?
First we can write a trait to check if T is derived from S, but not S:
template <class Base, class Derived>
using is_strict_base =
std::integral_constant<bool,
std::is_base_of<Base,Derived>::value &&
!std::is_same<Base,typename std::remove_cv<Derived>::type>::value>;
You can use std::enable_if to use this trait:
template<class T>
typename std::enable_if<is_strict_base<S,T>::value>::type
foo(T* instance)
{}
With C++14 you can use std::enable_if_t to make it a bit prettier:
template<class T>
std::enable_if_t<is_strict_base<S,T>::value>
foo(T* instance)
{}
Another option is to use static_assert:
template<class T>
void foo(T* instance)
{
static_assert(is_strict_base<S,T>::value,
"T must be derived from S, but not S");
}
This gives you a nicer error, but I personally believe that type constraints for a function belong in the declaration.

why cannot partially specialize a member function, in c++ template

I have code such as
template <class T> class Widget
{
void fun() {}
}
//Okay: specialization of a member function of widget
template <> void Widget<char>:: fun()
{
void fun() {}
}
But, below is error as I am been told. But not understand why.
template<class T, class U> class Gadget
{
void fun() {}
}
//Error! cannot partially specialize a member function of Gadget
template<class U> void Gadget<char,U>::fun()
{
..specialized implementation
}
Why is the second wrong? how to change it to make it right?
thanks!!!!
It is impossible to partially specialize just one single member function, you have to partially specialize the whole class. That's how things work in C++.
The reason is that you cannot have partially specialized functions, and member functions are themselves functions. By partially specializing the whole class, the member functions will "look" like templates with fewer types (in that partial specialized class).
Why you cannot have partially specialized functions is another story, and I don't have a good answer/understanding why is this enforced.
About making it work, why don't you partially specialize the class, then re-define only the function that you need.
One approach is to move that single function to a helper class template, which can be partially specialized:
template<class T, class U> class Gadget;
template<class T, class U>
struct Gadget_fun
{
static void do_it(Gadget<T,U>* This) {}
};
template<class T, class U> class Gadget
{
friend class Gadget_fun<T,U>;
void fun() { Gadget_fun<T,U>::do_it(this); }
};
template<class U>
struct Gadget_fun<char, U>
{
static void do_it(Gadget<char,U>* This)
{
//..specialized implementation
}
};
This way you don't have to duplicate all the other members as you would to specialize Gadget itself.