Note: The following question is about the Template Method Design Pattern and C++ function templates. To distinguish both, I will use italics when referring to the design pattern and bold when referring to C++ templates.
The idea of the template method pattern is to make parts of an algorithm exchangeable. This is usually achieved via inheritance, where the subclass provides concrete implementations that are plugged into an algorithm of the base class. However, if the hook methods need to be templates, this will not work as templates cannot be virtual. Here is a simple example that does not compile:
class Base
{
public:
// This is the template method
template <typename T>
void doSomething(T input)
{
//...
auto converted = ConvertInput(input);
//...
std::cout << converted;
}
protected:
//compile error "member function templates cannot be virtual"
template <typename T>
virtual T ConvertInput(T input) = 0;
};
class Derived : public Base
{
protected:
template <typename T>
T ConvertInput(T input)
{
return 2 * input;
}
};
int main()
{
Derived d;
d.doSomething(3);
}
Is there a way to implement template methods that use function template hooks?
I am not interested in using the Base class as a type anywhere. I will always use the concrete specific type to achieve a maximum of compile-time optimization. So another formulation of this question is: How can I create several classes Derived-1 .. Derived-n that have function templates that share a common code skeleton across the implementations?
Sounds like a fine use-case for CRTP. Define Base as a class template with the type derived from it as the template parameter. Inside Base's methods you can cast down to the derived type:
template<typename Derived>
struct Base
{
// This is the template method
template <typename T>
void doSomething(T input)
{
//...
auto converted = static_cast<Derived*>(this)->ConvertInput(input);
//...
std::cout << converted << std::endl;
}
};
And then define the derived types, for example:
struct Square : Base<Square>
{
template<typename T>
auto ConvertInput(T t)
{
return t*t;
}
};
struct Sum : Base<Sum>
{
template<typename T>
auto ConvertInput(T t)
{
return t+t;
}
};
the usage is pretty trivial:
Square sq;
Sum sum;
sq.doSomething(3);
sum.doSomething(3);
live demo
CRTP solves your problem by making Base a template.
If T comes from a finite set, or conversion is non arbutrary, type erasure can work.
If a finite set, type erase all the derived virtual methods. If common property, type erase that property and virtualize method that acts on it. Or a mixture.
Otherwise, Base can have template methods that take the operation as function object (with template operator()) instead of using virtual to find it. Derived passes the templated operations in as arguments to Base method(s). This is basically CRTP without CRTP.
Related
EDIT: I didn't actually get a chance to test out any of the suggested solutions as I went on a vacation, and by the time I was back, the people responsible for the class template had made some changes that allowed me to get around the need to use types defined in the class template itself.
Thanks to everyone for their help though.
In a nutshell - and feel free to correct my wording, templates are still a bit of voodoo to me, - I need to know if I can use a (protected) struct or a #typedef defined inside a class template from my specialized class. For example:
This is the class template:
template<typename T>
class A : public C<T>
{
protected:
struct a_struct { /* Class template implementation, doesn't depend on T */ };
void foo( a_struct a );
};
Which I need to fully specialize for T = VAL:
template<>
class A< VAL > : public C< VAL >
{
void foo( a_struct a )
{
// My implementation of foo, different from the class template's
}
};
If I do something like this, however, the compiler complains that a_struct is undefined in my specialized class. I tried specializing and inheriting from the class template but that got... messy.
I saw some solutions, but all of them involved modifying the class template, which is something I am not able to easily do (different team).
Thoughts?
No, you can't use members of the primary template declaration in your specialization of the class template. That is because in essence a template class specialization declares a completely new class template that is applied when the template arguments match the specialization.
You have two options available though, if you want to do something like in your example:
You can specialize the template class member function. This is useful if it is indeed only one member function that is special (or at least the number of member functions is limited).
You can bring the declaration of the member (-type) in a common base class.
Since you indicated in an edit that you can't change the class template itself, specializing the member function seems the best option.
A simplified example of specializing a member function only
template< class T>
class Printer
{
public:
struct Guard {};
void DoPrint( const T& val)
{
Guard g;
(void)g;
std::cout << val << '\n';
}
};
struct Duck {};
template<>
void Printer<Duck>::DoPrint( const Duck& val)
{
Guard g;
(void)g;
std::cout << "Some duck\n";
}
The Guard here is only used to demonstrate that this type is available to both the primary and the specialized implementation of DoPrint().
It's not beautiful, but you can do it like this:
template<typename T>
class C
{
};
template<typename T>
class A : public C<T>
{
protected:
friend A<int>;
// ^^^^^^
struct a_struct { /* Class template implementation, doesn't depend on T */ };
void foo( a_struct a );
};
template<>
class A< int > : public C< int >
{
using a_struct = typename A<void>::a_struct;
// ^^^^^^
void foo( a_struct a )
{
// My implementation of foo, different from the class template's
}
};
or how about, re-declaring struct a_struct in the specialized template, with same functionality as default one.
I know it may not sound good since you need to inject in all specialized templates. But that is one i can think of now.
Say I have a class template in which some methods are type specific.
template <typename T>
class Shape
{
...
void Foo();
...
};
Now I would specialize the type-specific functions using, for example:
void Shape<bool>::Foo() {...};
void Shape<double>::Foo() {...};
Question:
What if Foo should have different parameters depending on the type? Is it possible to specialize a method for a specific type using parameters different from the ones in the class declaration? I suspect it's not allowed, so how should it be done?
How to prevent class instantiation for types for which Foo hasn't been defined?
When should virtual and pure virtual functions should be used in contrast to the siutation I have described? Is it possible to mix both templates and inheritance?
1a . What if Foo should have different parameters depending on the type? Is it possible to specialize a method for a specific type using parameters different from the ones in the class declaration?
No. Yes, As pointed out by Nathan Monteleone below, this is possible by fully specializing the class Shape.
1b . I suspect it's not allowed, so how should it be done?
Can you turn the function itself into a template independent of the class
class Shape {
//...
template <typename T>
void Foo();
//...
};
2 . How to prevent class instantiation for types for which Foo hasn't been defined?
In the class body:
template<typename U> //note the different typename
class Shape {
static_assert(std::is_same<U, bool>::value || std::is_same<U, double>::value, "Type forbidden");
//...
inline void Foo() {
if( std::is_same<U, bool>::value ) Foo_impl_bool();
else if( std::is_same<U, double>::value ) Foo_impl_double();// and so on.
// this function is likely to get optimized since the conditionals are constexpr
}
private:
void Foo_impl_bool();//...
};
3a . When should virtual and pure virtual functions should be used in contrast to the situation I have described?
The answers to 1b and 2 are 2 separate solutions, if neither of them is possible the other possibilities are:
Extract that function into its own class.
Use interface inheritance for this function alone.
3b . Is it possible to mix both templates and inheritance?
Yes
(1) Sort of, but not quite the way you're trying to do it. You basically want the specializations to define the function; it's quite a bit different from when you are declaring base and derived classes.
template <typename T> class Shape {
static_assert(false, "Not implemented");
};
template <> class Shape<bool> {
void Foo(bool a, std::string b) {...}
};
template <> class Shape<int> {
void Foo(int, std::string, whatever else) {...}
};
Even if you were to define Foo in the original non-specialized Shape, it would have no effect on the specializations. Full specializations don't extend the original template, they replace it!
(2) Use static_assert. See the example above.
(3) Yes, you can mix templates and inheritence. Virtual functions runtime polymorphism and static polymorphism. Template parameters have to be known at compile time whereas the exact type of a runtime polymorphic object does not, because they can be referred to by a base class reference. In the templated example above you cannot simply say
template <class T> Shape {...};
...
Shape* myShape; // Compiler error: Shape requires a template parameter
However with inheritence you can:
class ShapeBase { virtual void Foo() = 0; };
class Circle : public ShapeBase { virtual void Foo() { ... } };
class Square : public ShapeBase { virtual void Foo() { ... } };
...
Shape* myShape = new Circle;
myShape->Foo(); // calls Circle->Foo()
Note when you're working with inheritence, the function signatures DO have to match! That's the price you pay for deferring the decision till runtime.
Please refer to the below code
Specialized function in non specialized Template class
Is it possible to write a specialized function foo, for non specialized template class MyClass [Line Number 7] ? If yes, then, what is the syntax for the same.
Regards,
Atul
This can be done if you create a full specialization of the class template. Just refer to the answer in this question: If I want to specialise just one method in a template, how do I do it?
Otherwise if you want to have a given function with the same signature have two different behaviors depending on the instantiated version of the class, and that instantiation is a partial specialization of the template class, you will have to make a separate specialization of the template class.
Keep in mind that if you want to avoid redundant code in this second case, you can always create a base template class that will have the functionality that will not change, and then create derived template classes that will contain the unique functionality necessary for each partial specialization.
Look at my example below, I have tried answer your question (if I guessed right) in the simplest code possible by me:
#include <iostream>
using namespace std;
template<typename T>
class Some
{
public:
template<typename U> void foo(U val);
};
template<typename T>
template<typename U>
void Some<T>::foo(U val)
{
cout << "Non specialized" << endl;
}
template<>
template<>
void Some<char>::foo(char val)
{
cout << "Char specialized" << endl;
}
int main()
{
Some<int> t1;
t1.foo(5);
Some<char> t2;
t2.foo('c');
return 0;
}
The important thing to note here is that "You cannot specialize your class and function Independently" i.e you have to specialize both at the same time as done in the example.
Also, with this you lose the opportunity to specialize your class for that data type "char" in this case. (Need to confirm on this).
UPDATE :: Confirmed on point 2.
If you wanted to specialize MyClass< bool >::Foo, it would look like this:
template <>
void MyClass<bool>::Foo(bool A)
{
// code goes here
}
If you are asking that,
(1) you want a function Foo() which doesn't take any argument and
returns void inside MyClass
(2) This Foo() should be exclusive to the MyClass when the
template type is bool, i.e. only for MyClass<bool>
then here is the way:
template<class Precision>
class MyClass {
...
public:
...
void Foo (); // don't implement here
};
...
template<>
void MyClass<bool>::Foo () // implementing only for 'MyClass<bool>'
{ // invoking for other 'MyClass<>' will result in compiler error
...
}
I'm wanting to invoke a specialized templated function by using a pointer to it's base type. I'm not sure if this possible so I'm open to suggestions and/or alternatives. Here is an example of my situation:
class CBase {};
class CDerivedClass : public CBase {};
template<class T>
int func<T>(T &x) { ... };
template<>
int func<CDerivedClass>(CDerivedClass &x) { ... };
I have another function that manages a list of CBase pointers and then calls the func() function.
void doStuff()
{
CBase *foo[10] = { ...... };
for (int i = 0; i < 10; ++i)
func(*foo[i]);
}
Is there a way to get the derived type, so that func(CDerivedClass &) is called?
What about Template Subclassing? This idiom allows you to use compile-time polymorphism in C++. The cost of it is higher verbosity (such as specifying the whole class hierarchy up to the current class). In your case:
template <typename TSpec> class Klass {};
template <typename TSpec> struct SpecTag {};
template <typename TSpec> class Klass<SpecTag<TSpec> > {};
template <typename TSpec>
int func(Klass<TSpec> &x) { ... };
template <typename TSpec>
int func(Klass<SpecTag<TSpec> > &x) { ... };
The "Visitor" pattern comes to the rescue in this case. It enables polymorphic behavior in an algorithm implemented outside the class. Some support code is required inside the class, but new algorithms can later be added, existing algorithms modified, etc., without affecting the class.
Alternative solution : from your example, it's obvious that you just should to use a virtual method in CBase, so you just have to define a virtual function in CBase and an overriding function in the derived class.
I have a template container class that I derive from called MyContainer. MyContainer defines methods like Get(), Set(), etc. to access individual elements. I'd like to make a bitfield class implemented as a MyContainer<char>, where each char element holds CHAR_BIT number of bits. However, to allow the user to operate on individual bits rather than entire bytes, I would have to make Get() and Set() virtual, which is illegal. What are some alternatives?
I was thinking of defining GetBit() and SetBit() in the derived class, but this would violate the Liskov substitution principle. (Think of a SortMyContainer() function.)
EDIT: Here is a simplified example:
template <typename Datatype>
struct MyContainer
{
virtual Datatype Get();
};
template <typename Datatype> // Error: Templates may not be virtual.
virtual Datatype MyContainer<Datatype>::Get() // EDIT: The problem was on this line. The "virtual" keyword should only appear with the function declaration.
{
// ...
}
It is not illegal, only template virtual member functions are.
// valid
template<typename T> class MyContainer {
virtual void set(const T &) = 0;
}
// not valid
class MyContainer {
template <typename T> virtual void set (const T &) = 0;
}
If I got you wrong, please consider placing a code-sample.
edit after your adding of example code:
template <typename Datatype>
virtual // <-- nope, not here
Datatype MyContainer<Datatype>::Get()
{
// ...
}
virtual is only part of the declaration inside the class body. This should be valid:
template <typename Datatype>
Datatype MyContainer<Datatype>::Get()
{
// ...
}
However, note that the definition must be visible at the point of template instantiation. So either put it in the header-file, too (or in an extra-header that you then include into your real header), or leave it in the class-body.
(please nobody mention exported templates now, you and I know them a lot, but they are not quite a beginner topic, and deprecated with the next standard)
You appear to be confused about what constitutes a template. Class templates may have virtual functions, and indeed, those template parameters may appear in those function's signatures.
template<typename T> class an_interface {
virtual T Get() = 0;
};
class a_class : public an_interface<int> {
};
This is perfectly valid. What's not perfectly valid is
class an_interface {
template<typename T> virtual T Get() = 0;
}
Unless the specific member function in question has it's own, separate template parameters, the member function is not a template and may be virtual, irrespective of if it was generated from a class template.