C++ - specialize class template's member function - c++

I am looking for help with templates. I need to create function in template what will be reacting differently on a specific type.
It could looks like this:
template <typename T>
class SMTH
{
void add() {...} // this will be used if specific function isn't implemented
void add<int> {...} // and here is specific code for int
};
I also tried to use typeid and swich through types in a single function, but doesn't work for me.

You really don't want to be doing this branching at runtime, with typeid.
We want this code:
int main()
{
SMTH<int>().add();
SMTH<char>().add();
return 0;
}
To output:
int
not int
There are lot of ways I can think of to achieve this (all at compile time and half of them requires C++11):
Specialize the whole class (if it has only this add function):
template <typename T>
struct SMTH
{
void add() { std::cout << "not int" << std::endl; }
};
template <>
struct SMTH<int>
{
void add() { std::cout << "int" << std::endl; };
};
Specialize only the add member function (recommended by #Angelus):
template <typename T>
struct SMTH
{
void add() { std::cout << "not int" << std::endl; }
};
template <> // must be an explicit (full) specialization though
void SMTH<int>::add() { std::cout << "int" << std::endl; }
Note that if you instantiate SMTH with cv-qualified int, you'll get the not int output for above approaches.
Use the SFINAE idiom. There are few variants of it (default template argument, default function argument, function return type), and the last one is the one that fits here:
template <typename T>
struct SMTH
{
template <typename U = T>
typename std::enable_if<!std::is_same<U, int>::value>::type // return type
add() { std::cout << "not int" << std::endl; }
template <typename U = T>
typename std::enable_if<std::is_same<U, int>::value>::type
add() { std::cout << "int" << std::endl; }
};
The main benefit is that you can make the enabling condition complex, e.g. using std::remove_cv to choose the same overload regardless of cv-qualifiers.
Tag dispatching - chooses the add_impl overload based on if the instantiated tag inherits from A or B, in this case std::false_type or std::true_type. You still use template specialization or SFINAE, but this time it's done on a tag class:
template <typename>
struct is_int : std::false_type {};
// template specialization again, you can use SFINAE, too!
template <>
struct is_int<int> : std::true_type {};
template <typename T>
struct SMTH
{
void add() { add_impl(is_int<T>()); }
private:
void add_impl(std::false_type) { std::cout << "not int" << std::endl; }
void add_impl(std::true_type) { std::cout << "int" << std::endl; }
};
This can of course be done without defining the custom tag class, and the code in add will look like this:
add_impl(std::is_same<T, int>());
I don't know if I mentioned them all, and I don't know why I attempted to, either. All you have to do now is to choose the one that fits the use the best.
Now, that I see, that you also wanted to check if a function exists. This is already long, and there's an existing QA about that.

Related

How do member variables work with specialized class templates?

I'm trying to write a very simple specialized class template that has a member variable and can print that member variable differently in specialized situations. I know the example is pretty useless, but it illustrates the question pretty well.
When specializing class templates it seems that the specializations of the class don't share the same member variables, so the following code won't compile...
#include <iostream>
#include <string>
// Class template
template <typename T>
struct S
{
S(const T& t)
: t(t)
{}
void print()
{
std::cout << t << std::endl;
}
private:
T t;
};
// Specialization
template <>
struct S<std::string>
{
void print()
{
// ERROR: "t" is not defined in this context
std::cout << "string: " << t << std::endl;
}
};
This suggests that I would need to write a separate constructor for every specialization and have a separate member variable t for each specialization which feels like it would quickly become a lot of duplicated code and effort if I have many specializations.
If what I am saying is true, then is it bad practice to use member variables in specialized class templates altogether? Are there any alternatives that result in less code duplication?
Please also look at #0x499602D2's answer, it is simpler and works for many practical cases.
You are correct, the specializations are basically totally independet from each other and the original template, so you would have to write everything new. A way to get around that would be to use inheritance.
#include <iostream>
#include <string>
// Class template
template <typename T>
struct Base
{
Base(const T& t)
: t(t)
{}
virtual void print()
{
std::cout << t << std::endl;
}
protected:
T t;
};
template<class T>
struct S: Base<T> {
};
// Specialization
template <>
struct S<std::string>: Base<std::string>
{
void print() override
{
std::cout << "string: " << t << std::endl;
}
};
Since you are only specializing a single template parameter, you can explicitly specialize the member function instead of the entire class:
template <>
void S<std::string>::print()
{
std::cout << "string: " << t << std::endl;
}
Another possible solution is tag-dispatcing
template <typename T>
struct S
{
private:
T t;
void print_helper (std::true_type) // T is std::string
{ std::cout << "string: " << t << std::endl; }
void print_helper (std::false_type) // T isn't std::string
{ std::cout << t << std::endl; }
public:
S (T const & t0) : t{t0}
{ }
void print ()
{ print_helper(std::is_same<T, std::string>{}); }
};
Another way to do it is to use a helper function. This will let you do partial template specialization kind of, working around the issue noted by #0x499602D2. What we're doing is having the templated function call a helper function and the helper function is doing all the specialization.
I added another template parameter into there to show that this solution kind of works for partial template specialization. Notice that the templated helper function is full-specialized, not partially. You can't partially specialize a function. This can be useful in cases when the class template has more template parameters that you can't specialize (UNUSED_T) but the function that you do want to specialize can be fully specialized (print_it doesn't need the UNUSED_T).
#include <iostream>
#include <string>
// This is the helper function for all types T...
template <typename T>
void print_it(T t) {
std::cout << t << std::endl;
}
// ... except for std::string, it will run this one.
template <>
void print_it<std::string>(std::string t) {
std::cout << "string: " << t << std::endl;
}
// Class template, UNUSED is there just to show that
// this works for partial template specialization.
template <typename T, typename UNUSED_T>
struct S {
S(const T& t) : t(t) {}
void print() {
// You can remove the <T> because
// the compiler will figure it out for you.
print_it<T>(t);
}
prviate:
T t;
UNUSED_T unused;
};
int main() {
S<uint, char> x(5);
x.print(); // OUTPUT: 5
S<std::string, char> y("foo");
y.print(); // OUTPUT: string: foo
}

Template class specialization for vector type - different valid syntax?

In the following snippit, is the template<> optional for the specialization? Is there any difference whether I include it or not? My first instinct was to include it as it more-or-less signifies that it is a specialization. It compiles both ways under both g++ 4.9.2 and Intel 16
#include <vector>
#include <iostream>
template<typename T>
struct PrintMe
{
static void Print(const T & t)
{
std::cout << "In general templated struct: " << t << "\n";
}
};
template<> // <--- optional?
template<typename T>
struct PrintMe<std::vector<T>>
{
static void Print(const std::vector<T> & t)
{
std::cout << "In general specialization for vector: " << t.size() << "\n";
for(const auto & it : t)
std::cout << " " << it << "\n";
}
};
int main(void)
{
PrintMe<int>::Print(5);
PrintMe<double>::Print(5);
PrintMe<std::vector<float>>::Print({10,20,30,40});
return 0;
}
Note: Out of curiosity, I tried adding multiple template<>. Ie,
template<>
template<>
template<>
template<typename T>
struct PrintMe<std::vector<T>>
This still compiles with Intel, but not with g++. Not sure what that means, but it's interesting.
Note 2: Wow, this is very similar to a question of mine from 5 years ago: Templated class specialization where template argument is a template . There it was mentioned as redundant syntax.
Given the definition of the class template,
template<> // <--- optional?
template<typename T>
struct PrintMe<std::vector<T>> { ... };
is not valid.
You need to remove that line and use:
template<typename T>
struct PrintMe<std::vector<T>> { ... };
there are ways to look at templates and template specialization that will paint a better picture and make the whole thing clearer.
For me in this case the easier way to look at this is not to think of
template<typename T>
struct PrintMe<std::vector<T>> { ... };
as a specialization of
template<typename T>
struct PrintMe { ... };
but as a different class template altogether, it just happen to be that the two have similarly named methods.

C++11 method template specialization for return type

I've got following class:
class Foo {
public:
template <typename T>
T bar() {
cout << "Called with return type: " << typeid(T).name() << endl;
T t = //... (some implementation here)
return t;
}
}
It's invoked in following way:
Foo foo;
int i = foo.bar<int>();
long l = foo.bar<long>();
Now i'd like to have different specialization for cases when function is invoked with shared_ptr<T>
Foo foo;
foo.bar<shared_ptr<int>>();
foo.bar<shared_ptr<long>>();
But of course I don't want to create full specialization for each type. Is it possible to implement such behaviour (can be trait-based if required)?
You cannot partially specialize functions. For a story on why, check out this GOTW.
You can partially specialize classes though, so what you could do is:
template <typename T>
T bar() {
return bar_impl<T>::apply(this);
}
Where:
template <typename T>
struct bar_impl {
static T apply(Foo* ) {
// whatever
}
}
template <typename T>
struct bar_impl<std::shared_ptr<T>> {
static std::shared_ptr<T> apply(Foo* ) {
// whatever else
}
}
There's certainly many ways to do it. The first way that comes to my mind is simply function overloading. Since you don't have a parameter to overload on, you'll have to make one. I like pointers, which effectively act as a way to pass types to functions.
class Foo {
//regular overload
template<typename T>
T bar(T*) { //takes a pointer with an NULL value
cout << "Called with return type: " << typeid(T).name() << endl;
T t = //... (some implementation here)
return t;
}
//shared_ptr overload - NOTE THAT T IS THE POINTEE, NOT THE SHARED_PTR
template<typename T>
std::shared_ptr<T> bar(std::shared_ptr<T>*) { //takes a pointer with an null value
cout << "Called with return type: " << typeid(T).name() << endl;
std::shared_ptr<T> t = //... (some implementation here)
return t;
}
public:
template <typename T>
T bar() {
T* overloadable_pointer = 0;
return bar(overloadable_pointer);
}
};
I've never heard of anyone else using pointers to pass types around, so if you choose to do this, comment thoroughly, just to be safe. It is wierd code.
It may be more intuitive to simply use a helper struct to do template specialization, which is what most people would do. Unfortunately, if you need access to the members of Foo (which you presumably do), using template specialization would require you to pass all those members to the function, or friend the template helpers. Alternatively, you could pass a type_traits specialization thing to another member, but that ends up simply being a complex version of the pointer trick above. Many find it more normal and less confusing though, so here's that:
template<typename T>
struct Foo_tag {};
class Foo {
//regular overload
template<typename T>
T bar(Foo_tag<T>) {
}
//shared_ptr overload - NOTE THAT T IS THE POINTEE, NOT THE SHARED_PTR
template<typename T>
std::shared_ptr<T> bar(Foo_tag<std::shared_ptr<T>>) {
}
public:
template <typename T>
T bar() {
return bar(Foo_tag<T>{});
}
}
Since noone proposed it yet, one can use SFINAE to distinguish between T and std::shared_ptr<U>:
template <typename T>
struct is_shared_ptr_impl : std::false_type {};
template <typename T>
struct is_shared_ptr_impl<std::shared_ptr<T>> : std::true_type {};
template <typename T>
using is_shared_ptr = typename is_shared_ptr_impl<typename std::decay<T>::type>::type;
class Foo
{
public:
template <typename T>
auto bar()
-> typename std::enable_if<!is_shared_ptr<T>{}, T>::type
{
std::cout << "T is " << typeid(T).name() << std::endl;
return {};
}
template <typename T>
auto bar()
-> typename std::enable_if<is_shared_ptr<T>{}, T>::type
{
using U = typename std::decay<T>::type::element_type;
std::cout << "T is shared_ptr of " << typeid(U).name() << std::endl;
return {};
}
};
DEMO

How to determine whether the template type is a basic type or a class

I have code something like this
template <typename T> void fun (T value)
{
.....
value.print (); //Here if T is a class I want to call print (),
//otherwise use printf
.....
}
Now, to print the value, if T is a class, I want to call the print function of the object, but if T is a basic datatype, I just want to use printf.
So, how do I find if the Template type is a basic data type or a class?
You could use std::is_class (and possibly std::is_union). The details depend on your definition of "basic type". See more on type support here.
But note that in C++ one usually overloads std::ostream& operator<<(std::ostream&, T) for printing user defined types T. This way, you do not need to worry about whether the type passed to your function template is a class or not:
template <typename T> void fun (T value)
{
std::cout << value << "\n";
}
Recommend overloading operator<<(std::ostream&) for any type T instead of using printf(): how would you know what format specifier to use?
template <typename T> void fun (T value)
{
.....
std::cout << value << std::endl;
.....
}
FWIW, std::is_class exists.
If you don't have C++11 support, an alternative.
template<typename T>
class isClassT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename C> static One test(int C::*);
template<typename C> static Two test(…);
public:
enum { Yes = sizeof(isClassT<T>::test<T>(0)) == 1 };
enum { No = !Yes };
};
A simple template for finding out if type is class type. More in C++ Templates a Complete Guide.
if (isClassT<T>::Yes) {
std::cout << " Type is class " << std::endl;
}
I'd go with a printing helper function template/overload:
template <typename T>
void print(T const & t) { t.print(); }
template <typename U>
void print(U * p) { std::printf("%p", static_cast<void*>(p)); }
// we really an enable_if on is_object<U>::value here...
void print(char x) { std::printf("%c", x); }
void print(int x) { std::printf("%d", x); }
// etc. for all fundamental types
Then you can simply say print(value); in your code.

partial specialization of function templates

In the below code snippet,
template<typename T1>
void func(T1& t)
{
cout << "all" << endl;
}
template<typename T2>
void func(T2 &t)
{
cout << "float" << endl;
}
// I do not want this
// template<> void func(float &t)
int main()
{
int i; float f;
func(i); // should print "all"
func(f); // should print "float"
return 0;
}
I would like to have the templates modified which by passing any type other than float will print "all" and passing float will print "float". I do not want template specialization, instead have partial specialization which will act accordingly based on input type. How should i go about it. Thanks in advance.
Well the scenario, i'm currently facing is like,
I need to have the following defined,
template<typename T1>
void func(T1 &t)
{
cout << "t1" << endl;
}
template<typename T2>
void func(T2 &t)
{
cout << "t2" << endl;
}
The following calls should print "t2"
func(int) // print "t2"
func(float) // print "t2"
func(string) // print "t2"
The following calls should print "t1"
func(char) // print "t1"
func(xyz) // print "t1"
...
func(abc) // print "t1"
some kind of grouping like the above where few should call the partial specialization implementation and others should call the default implementation.
You can combine function overloading with templates. So:
#include <iostream>
template<typename T>
void func(T& t)
{
std::cout << "all" << std::endl;
}
void func(float& f)
{
std::cout << "float" << std::endl;
}
int main()
{
int i; float f;
func(i); // prints "all"
func(f); // prints "float"
return 0;
}
Write a type traits class for your condition:
template<class T>
struct IsIntFloatOrString {
enum { value = boost::is_same<T, int>::value
or boost::is_same<T, float>::value
or boost::is_same<T, string>::value };
};
Use boost::enable_if and disable_if:
template<typename T1>
typename boost::enable_if<IsIntFloatOrString<T1> >::type
func(T1 &t) {
cout << "t1" << endl;
}
template<typename T2>
typename boost::disable_if<IsIntFloatOrString<T2> >::type
func(T2 &t) {
cout << "t2" << endl;
}
You cannot partially specialise functions in C++.
Perhaps this is not the terminology you mean. You can use templates like boost::is_same<T1, T2> to perform conditional logic based on the given template parameter. You can also use T in any place where you'd use any other type, such as in typeid(T).name():
template <typename T>
void foo(T&) {
if (boost::is_same<T, int>::value)
std::cout << "int lol";
else
std::cout << typeid(T).name();
}
(Although I'd not recommend using typeid().name() as its value is not specified by the standard and can vary from the type written in your code, to a mangled symbol, or the lyrics to Pokerface.)
Addendum Like other answerers, I would personally choose template specialisation itself or just plain ol' function overloading. I don't know why you're averse to them, but that is what they are there for.
As Tomalak already said in his answer you can not partially specialize a template function, but if you change your function to be a static member function in a template class, you could do it.
However, a better approach would be function overloading.
This is how to make it work without ugly syntax a and !b and !c for enable_if in case of arbitrary number of conditions.
If we know that partial specialization don't work work function but work with classes, let's use classes! We should hide it from people, but we can use them!
OK, code:
#include <type_traits>
#include <iostream>
template <typename T>
class is_int_or_float : public std::integral_constant<bool, std::is_same<T, int>::value || std::is_same<T, float>::value> {
};
template<typename T, typename Enable = void> //(2)
struct Helper {
static void go(const T&) {
std::cout << "all"<< std::endl;
}
};
template<typename T>
struct Helper<T, typename std::enable_if<is_int_or_float<T>::value>::type> { // (3)
static void go(const T&) {
std::cout << "int or float" << std::endl;
}
};
template<typename T>
struct Helper<T, typename std::enable_if<std::is_pointer<T>::value>::type> { // (3)
static void go(const T&) {
std::cout << "pointer" << std::endl;
}
};
template<typename T>
void func(const T& arg) {
Helper<T>::go(arg); // (1)
}
int main() {
char c;
int i;
float f;
int* p;
func(c);
func(i);
func(f);
func(p);
}
(1) First of all just for every type call helper. No specialization for functions.
(2) Here we add one dummy argument. We don't have to specify it on calling because it's default to void
(3) In 3 we just give void, when we allow T and anything else (or SFINAE as in our case). One important thing is that we shouldn't allow some T twice or more.
Notes:
We can also change default type to std::true_type, after that we will be able to get rid of std::enable_if (std::enable_if<some_trait<T>::value> will be change to just some_trait<T>::type). I'm not sure which
This code uses type traits from C++11. If you don't have c++11 support you may write your own traits or use type traits from boost
Live example