Specialise only parts of template class while keeping the rest generic - c++

Assuming the following class:
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100(); // basically many functions already defined
}
How can I add another function to a specialisation of the class while not rewriting all possibly 100 functions that are already templated?
template<>
class Test<int> {
public:
void do_something_else();
}
...
int main() {
auto x = Test<int>();
x.do_something5(); // should be still valid, would call
// Test<T>::do_something5() with T being int
x.do_something_else(); // valid because declared in specialisation
...
}
Right now, if the Test<int> specialisation is left as in the example above, it would only contain do_something_else(), without do_something1...100().
Solution
Based on the accepted answer, using the given example, I did the following:
namespace parent {
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100();
}
}
template <typename T>
class Test : public parent::Test<T> {
using parent::Test<T>::Test; // inherit constructors
}
template <>
class Test<int> : public parent::Test<int> {
using parent::Test<int>::Test;
public:
void do_something_else();
}

You can create a common base class, and make both the primary template and specialization deriving from it.
Or you can make do_something_else function template and only works with int (then don't need using specialization).
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100(); // basically many functions already defined
template <typename X = T>
std::enable_if_t<std::is_same_v<X, int> && std::is_same_v<X, T>> do_something_else();
};
Or since C++20 we can use Constraints as #aschepler suggested.
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100(); // basically many functions already defined
void do_something_else() requires std::is_same_v<T, int>;
};

Related

Template Specialization with Template for Static Function

I have a template that inherits from another template, with itself as the second template's template parameter. The inherited template defines a static function:
template<class T> class A
{
public:
static void foo();
};
template<class T> class B : public A<B>
{
};
Now I want to implement the static function for the class A specialized with B, but with B not specialized. But I can't figure out how to declare the template. I'm not even sure if this is possible. My first try was:
template<class T> void A<B<T>>::foo()
{
}
But this gives the error:
"Nested name specifier 'A<B<T>>::" for declaration does not refer into a class, class template or class template partial specialization"
I've tried different things like adding "template<>" in front but none of those worked. I am able to compile this:
template<> void A<B<int>>::foo()
{
}
As well as this:
template<class T> void A<T>::foo()
{
}
Is this an attempt at partial specialization? My first impression is no (there are no templates with multiple parameters where I want to specialize one of them). Rather, I want to specialize a template with another template that is not specialized. Is this possible, and if so what is the proper syntax?
This is indeed partial specialization. You cannot partially specialize just a method, you must partially specialize the whole class. See this answer. You might try implementing foo in a separate helper struct and partially specializing that struct instead.
Here is an example using a helper struct.
#include <iostream>
template<class T> struct t_helper
{
static void foo()
{
std::cout << "Not B<T>\n";
}
};
template<class T> class A
{
public:
static void foo() {
t_helper<T>::foo();
}
};
template<class T> class B {};
// Specialize the behavior of A<T>::foo() for all B types
template<class T>
struct t_helper<B<T>>
{
static void foo()
{
std::cout << "Is B<T>\n";
}
};
int main()
{
A<int>::foo(); // Prints "Not B<T>\n"
A<B<int>>::foo(); // Prints "Is B<T>\n"
return 0;
}

Call the unspecialized template method from a specialized template method

Can I call an unspecialized template method from a specialized one?
This is easy when using inheritance:
class SomeBaseClass {
virtual void DoWork() { /* Do something */ }
};
class SomeClass : public SomeBaseClass {
void DoWork() {
// Do something first
SomeBaseClass::DoWork();
}
};
But is a bit different when using templates:
template <class T>
class SomeClass {
void DoWork();
};
template<class T>
void SomeClass<T>::DoWork() { /* Do something */}
template<>
void SomeClass<int>::DoWork() {
// Do something first
DoWork<>(); // Call method from line 8
}
My generic DoWork function has a lot of really good code in it that I'd hate to duplicate. My specialized one just has an extra step that it needs to perform when a specific type is used.
Similar to here, you can do that indirectly:
template <class T>
class SomeClassCommonImpl {
void DoWork();
};
template<class T>
void SomeClassCommonImpl<T>::DoWork() { /* Do something */}
template <class T>
class SomeClass: public SomeClassCommonImpl<T> {
// use the default implementation
};
template <>
class SomeClass<int>: public SomeClassCommonImpl<int> {
void DoWork();
};
template<>
void SomeClass<int>::DoWork() {
// Do something first
SomeClassCommonImpl<int>::DoWork<>(); // Call the common method
}
You're thinking about this the wrong way.
The solution is not to have your class specialized, but to have your function specialized. What I mean here is to use tag dispatch
That is, declare two private helper functions in your class named DoWorkHelper, one of which is overloaded for the specialized type, and the other not.
The way we do this is to wrap our type in a 'tag' that is basically an empty struct, and then specialize the tag for our type of interest:
namespace SomeClassDetail{
template<class T>
struct specialized_tag : std::false_type{};
template<>
struct specialized_tag<int>: std::true_type{};
}
true_type and false_type are essentially wrappers for boolean true and false. They're nice because they're types and not values (and when we template we care all about types)
Next, we'll declare our class with aforementioned overloads:
template <class T>
class SomeClass {
public:
void DoWork();
private:
void DoWorkHelper(std::true_type);
void DoWorkHelper(std::false_type);
};
The idea here is that true_type means "Yes, this function is for the specialized version!"
Here's what the definitions look like:
template<class T>
void SomeClass<T>::DoWork()
{
DoWorkHelper(typename SomeClassDetail::specialized_tag<T>::type{});
}
template<class T>
void SomeClass<T>::DoWorkHelper(std::true_type)
{
std::cout << "Specialized DoWork\n";
DoWorkHelper(std::false_type());
}
template<class T>
void SomeClass<T>::DoWorkHelper(std::false_type)
{
std::cout << "Unspecialized DoWork\n";
}
That's it. The specialized version will do its thing, and then call the unspecialized version, and the unspecialized version (for all other T), will simply do its thing.
Here's a live demo that demonstrates tag dispatch in action

Function specialized with template

I need to make a specialization of my function with template class and have problem with "illegal use of explicit template arguments".
template <typename T>
class MyClass { /* ... */ }; // it can be any template class, eg std::vector
template <typename T>
void foo() { /* ... */ } // my template function which need a specialization
template<>
void foo<int>() /* sth special for integers - it works */ }
template<template T>
void foo<MyClass<T> >() /* sth special for template class with any parameter - it doesnt work :( */ }
Of course i can type a few specialization for all MyClass'es which i need to, but maybe it can be replaced with one?
Template specialization of function is not as flexible as specialization of struct: only full specialization is allowed. If you want to do partial specialization you need to wrap your foo function inside a struct:
template <typename T> class MyClass { };
template <typename T> struct Foo;
template <typename T> struct Foo { void foo() {}};
template<> struct Foo<int> { void foo() { } };
template<typename T> struct Foo< MyClass<T> > { void foo() {} };
And then instead of calling
foo<MyClass<...>>()
you call
Foo< MyClass<...> >::foo()
You cannot partially speciallise a template function. There are discussions about removing that restriction though.
The advocated workarounds are:
Use a class template from the template function.
Wrap your function in a template class.
template <typename T>
struct foo_impl {
};
template <typename T>
void foo() {
foo_impl<T>();
}
// And now specialize foo_impl as you want:
template<>
struct foo_impl<int> {
foo_impl(){/* sth special for integers - it works */}
};
template<typename T>
struct foo_impl<myclass<T>> {
foo_impl() {/* ... */}
};
If you wanted a return-value, you should use a member-function - probably operator() - instead of the ctor.
This is a lot of extra typing, but how about:
template <typename T>
class MyClass { /* ... */ }; // it can be any template class, eg std::vector
template<typename T>
struct FooWrapper
{
static void foo()
{
// default implementation
}
};
template<typename T>
struct FooWrapper<MyClass<T>>
{
static void foo()
{
// MyClass<T> implementation
}
};
template<typename T>
void foo()
{
FooWrapper<T>::foo();
}
A possible solution could be using a base class
template<typename T> class MyClass;
class base {
private:
template<typename T> friend class MyClass;
base(); // Can't build a base object directly
};
template <typename T>
class MyClass : public base {
public:
}; // it can be any template class, eg std::vector
template <typename T>
void foo() {
} // my template function which need a specialization
template<>
void foo<int>() { /* sth special for integers - it works */ }
template<>
void foo<base>() { /* sth special for template class with any parameter - it doesnt work :( */ }
The above might also work in case you want a template parameter to your function. If you can wrap your function up I'd go with hivert's solution.

Strange class template specialization

I have a class template
template <class T>
class A
{
};
and very strange specialization
template <>
class A<class T*> : private A<void *>
{
};
Can anybody explain the meaning of this construction ?
The obfuscation declares a class T and specialize the template for T*
#include <iostream>
template <class T>
class A
{
public:
static void f() { std::cout << "Template" << '\n'; }
};
// Declare a class T and specialize the template for T*
template <>
class A<class T*> : private A<void *>
{
public:
static void f() { std::cout << "Specialization" << '\n'; }
};
class T {};
int main()
{
// Template
A<int*>::f();
// Specialization
A<T*>::f();
}
I think that the intended code would be:
template <class T>
class A<T *> : public A<void*>
{
};
That is a partial specialization that will be used for any pointer type, instead of the generic one. That is, any time A is instantiated using a pointer type, it will use this declearation instead of the generic one.
Naturally you need to instantiate, or otherwise spezialize the A<void*>, before this declaration, or else you will have an infinite recursion:
template class A<void*>;
This is a somewhat common idiom to force the compiler to reuse code. That is, you know that every instance of A<T*> is basically the same, as all pointers will behave identically under the hood. So you provide the full instantiation of A<void*> and then any other A<T*> inherits from it, doing the casts inline where needed.
Since A<T*> inherits from A<void*> it does not need to provide the bulk of the class code in its instantiation. Smaller code will hopefully will yield better performance.
Full example ahead, untested:
template <typename T>
class A
{
public:
A()
:m_data(0)
{}
void set(T x)
{ m_data = x; }
T get()
{ return m_data; }
//here there will be more complex operations
private:
T m_data;
//and a lot of data depending on T
};
template class A<void*>; //splicit instantiation
template <typename T>
class A<T*> : public A<void*>
{
private:
typedef A<void*> base_type;
public:
//only the public, and maybe protected, functions are needed
//but the implementation is one-line each
void set(T *x)
{ base_type::set(x); }
T *get()
{ return static_cast<T*>(base_type::get()); }
};

How to create specialization for a single method in a templated class in C++?

Many questions have been asked and they are similar to the one I am going to ask here, but they are not the same I think.
I have a templated class:
namespace app {
template <typename T>
class MyCLass {
public:
void dosome();
void doother();
}
} /*ns*/
And implementations:
template <typename T>
app::MyClass<T>::dosome() {}
template <typename T>
app::MyClass<T>::doother() {}
When I have an instance of that class to which a char is provided as template parameter, I want function dosome() to behave in a totally different way.
But I just want that function to behave differently, everything else must still act the same.
I tried typing:
template<>
app::MyCLass<char>::dosome() {
}
But the compiler tells me that I am trying to create a specialization in a different namespace.
So when I have a code like this:
app::MyCLass<int> a;
app::MyCLass<char> b;
a.dosome(); // This must call the generic template definition
b.dosome(); // This must call the specialization
a.doother(); // This must call the generic template definition
b.doother(); // This must call the generic template definition
In other questions I saw people creating totally different specialization of the entire class. But I only want a specialization of a single method.
You can do what you want: http://ideone.com/oKTFPC
// Header
namespace My
{
template <typename T>
class MyClass {
public:
void dosome();
void doother();
};
template <typename T> void MyClass<T>::dosome() {}
template <typename T> void MyClass<T>::doother() {}
template<> void MyClass<char>::dosome();
}
// cpp or in header
template<>
void My::MyClass<char>::dosome() {
std::cout << "specialization" << std::endl;
}
or using alternate notation
namespace My {
template<>
void MyClass<char>::dosome() {
std::cout << "specialization" << std::endl;
}
}
One option would be tag dispatching:
template <typename T>
class MyClass {
public:
void dosome() { dosome_impl( T() ); }
private:
void dosome_impl(char) { /* char stuff */ }
template<typename U>
void dosome_impl(U) { /* usual stuff */ }
};
Another one is enable_if idiom:
#include <type_traits>
template <typename T>
class MyClass {
public:
template<typename U = T>
typename std::enable_if<std::is_same<U,char>::value>::type
dosome() { /* char stuff */ }
template<typename U = T>
typename std::enable_if<!std::is_same<U,char>::value>::type
dosome() { /* normal stuff */ }
};
And yet another one is to move that single function to a base class that you can specialize:
template <typename T>
struct MyClass_base {
dosome() { /* usual stuff */ }
};
template<>
struct MyClass_base<char> {
dosome() { /* char stuff */ }
};
template <typename T>
class MyClass : private MyClass_Base<T> {
public:
// nothing special here
};