Type condition in template - c++

Is it possible to build only some part of the code given the type of the template in C++ ?
It would be something lake that :
#include <iostream>
using namespace std;
template<typename T>
void printType(T param)
{
#if T == char*
cout << "char*" << endl;
#elif T == int
cout << "int" << endl;
#else
cout << "???" << endl;
#endif
}
int main()
{
printType("Hello world!");
printType(1);
return 0;
}

Type traits:
#include <iostream>
#include <type_traits> // C++0x
//#include <tr1/type_traits> // C++03, use std::tr1
template<typename T>
void printType(T param)
{
if(std::is_same<T,char*>::value)
std::cout << "char*" << endl;
else if(std::is_same<T,int>::value)
std::cout << "int" << endl;
else
std::cout << "???" << endl;
}
Or even better yet, just overload the function:
template<class T>
void printType(T partam){
std::cout << "???" << endl;
}
void printType(char* partam){
std::cout << "char*" << endl;
}
void printType(int partam){
std::cout << "int" << endl;
}
Partial ordering will take care that the correct function is called. Also, overloading is preferred to template specialization in the general case, see this and this artice for why. Might not apply for you if you totally have to print the type, as implicit conversions are considered for overloaded functions.

Since C++17 there is a way to do exactly this with if-constexpr. The following compiles since clang-3.9.1, gcc-7.1.0, and recent MSVC compiler 19.11.25506 handles well too with an option /std:c++17.
#include <iostream>
#include <type_traits>
template<typename T>
void printType(T)
{
if constexpr (std::is_same_v<T, const char*>)
std::cout << "const char*" << std::endl;
else if constexpr (std::is_same_v<T, int>)
std::cout << "int" << std::endl;
else
std::cout << "???" << std::endl;
}
int main()
{
printType("Hello world!");
printType(1);
printType(1.1);
return 0;
}
Output:
const char*
int
???

Use template specialization:
template<typename T>
void printType(T param)
{
// code for the general case - or omit the definition to allow only the specialized types
}
template<>
void printType<char*>(char* param)
{
// code for char*
}
template<>
void printType<int>(int param)
{
// code for int
}
// ...

You can use a specialization. The preprocessor runs before all templates and cannot interact with them.
template<typename T> void printType(T t) {
std::cout << typeid(T).name(); // fallback
}
template<> void printType<char*>(char* ptr) {
std::cout << "char*";
}
template<> void printType<int>(int val) {
std::cout << "int";
}

You use template specification to specify versions of your function to work differently based on its type. For example, you can make a generic version of a function that would work with most types, and make a specific version for e.g. int that will be faster. You'd do it this way:
template <class T>
void printType(T param)
{
cout<<"Generic version"<<endl;
}
template <>
void printType<int>(int param)
{
cout<<"Int version"<<endl;
}
template <>
void printType<char>(char param)
{
cout<<"Char version"<<endl;
}
//Rince and repeat.

Related

Specify behavior of a class member function based on type passed C++

A simplified example of my code:
namespace Example
{
class A
{
public:
template<typename T>
void foo(T &val);
template<>
void foo<long>(long &val);
};
template<typename T>
void A::foo(T &val)
{
std::cout << "Generic Function: " << val << std::endl;
}
template<>
void A::foo<long>(long &val)
{
std::cout << "Specialized Function: " << val << std::endl;
}
}
I get an error like:
explicit specialization in non-namespace scope
Why doesn't template specialization work here? How can I specify the behavior of a member function based on the type that's passed in?
You don't need specialization for this, simple overloading will work fine (ie, remove the template<> from the 2nd foo()), eg:
namespace Example
{
class A
{
public:
template<typename T>
void foo(T &val);
void foo(long &val);
};
template<typename T>
void A::foo(T &val)
{
std::cout << "Generic Function: " << val << std::endl;
}
void A::foo(long &val)
{
std::cout << "Specialized Function: " << val << std::endl;
}
}
Online Demo
Or, in C++17 and later, you can just get rid of the 2nd foo() altogether and use if constexpr inside the implementation of the 1st foo(), eg:
#include <type_traits>
namespace Example
{
class A
{
public:
template<typename T>
void foo(T &val);
};
template<typename T>
void A::foo(T &val)
{
if constexpr (std::is_same_v<T, long>)
std::cout << "Specialized Function: " << val << std::endl;
else
std::cout << "Generic Function: " << val << std::endl;
}
}
Online Demo

Using function templates instead of template specialization

I am specializing template functions when intel intrinsic computation is available. In my case SSE and AVX. I want to produce a test program where I cal the non-specialized template function and the specialized one to compare performance. However, I do not know how to call the non-specialized template function for the type that it is specialized.
Here is a simplified example:
#include <iostream>
template <typename T>
void f(T val)
{
std::cout << "Template function. Value: " << val << std::endl;
}
template <>
void f(float val)
{
std::cout << "Float function. Value: " << val << std::endl;
}
int main()
{
f(1);
f(1.0f);
return 0;
}
Question: is there a way to call f(1.0f) with the non-specialized template function without changing function names?
Clarification: In my case, the two functions are provided in a library as part of the same pair of header and implementation file. Then this is included (for the template) and linked (for the specialization) in the program.
You can add an extra parameter to prohibit specialization:
#include <iostream>
template <typename T, bool enable_specialization = true>
void f(T val)
{
std::cout << "Template function. Value: " << val << std::endl;
}
template <>
void f<float, true>(float val)
{
std::cout << "Float function. Value: " << val << std::endl;
}
int main()
{
f(1.0f);
f<float, false>(1.0f);
return 0;
}
online compiler
Option N°2:
#include <iostream>
template <typename T>
void f(T val)
{
std::cout << "generic" << val << std::endl;
}
void f(float val)
{
std::cout << "Target specific" << val << std::endl;
}
int main()
{
f(1); //=> generic
f(1.0f); //=> target specific
f<float>(1.0f); //=> generic
return 0;
}

C++ specialise function on enum

Is it possible to specialise a template function on an enum?
I've seen noted here a template function can be disabled if it isn't an enum, but is this possible whilst still allowing other types?
My example below shows specialisations for int, float, and enum (it doesn't compile because it tries to overload the enum version rather than specialising it). I feel I'm missing something obvious.
Note that I'm looking to specialise on any enum, not just a named one (EAnEnum in the example)
#include <iostream>
enum class EAnEnum
{
Alpha,
Beta,
};
template<typename T>
void MyFunc();
template<>
void MyFunc<int>()
{
std::cout << "Int" << std::endl;
}
template<>
void MyFunc<float>()
{
std::cout << "Float" << std::endl;
}
// MyFunc<Enum>
template<typename T>
typename std::enable_if<std::is_enum<T>::value, void>::type MyFunc()
{
std::cout << "Enum" << std::endl;
}
int main()
{
MyFunc<EAnEnum>();
return 0;
}
You cannot partially specialize a function, but you can use tag dispatching instead.
It follows a minimal, working example based on the OP's question:
#include <iostream>
#include<type_traits>
enum class EAnEnum
{
Alpha,
Beta,
};
template<typename>
struct tag {};
void MyFunc(tag<int>)
{
std::cout << "Int" << std::endl;
}
void MyFunc(tag<float>)
{
std::cout << "Float" << std::endl;
}
void MyFunc(tag<EAnEnum>)
{
std::cout << "Enum" << std::endl;
}
template<typename T>
void MyFunc() {
MyFunc(tag<std::decay_t<T>>{});
}
int main()
{
MyFunc<EAnEnum>();
return 0;
}
You can easily add a parameter pack to be forwarded to the right MyFunc and still use this technique to solve your problem.
Of course, you can now specialize for any enum.
You can also provide a fallback MyFunc as:
template<typename T>
void MyFunc(tag<T>)
{
std::cout << "Fallback" << std::endl;
}
If you want a fallback for all the possible enum types, you can now rely on SFINAE, for these are different overloaded functions:
template<typename T>
std::enable_if_t<std::is_enum<T>::value>
MyFunc(tag<T>)
{
std::cout << "Fallback for enums only" << std::endl;
}
Note that you should not use directly the implications of MyFunc that accept a tag specialization as an entry point.
Those are meant as internal functions.
Use instead the generic one, as shown in the example.
You cannot partially specialize a function template, but can you just let it forward to a class template.
Since your function doesn't have arguments that's particularly easy:
#include <iostream>
#include <type_traits>
namespace impl {
using namespace std;
template< class Type, bool is_enum_ = is_enum<Type>::value >
struct Foo;
template< class Type >
struct Foo<Type, true>
{ void func() { cout << "Enum" << endl; } };
template<>
struct Foo<int>
{ void func() { cout << "Int" << endl; } };
template<>
struct Foo<float>
{ void func() { cout << "Float" << endl; } };
} // namespace impl
template< class Type >
void foo()
{ impl::Foo<Type>().func(); }
auto main()
-> int
{
enum class An_enum
{
alpha, beta,
};
foo<An_enum>();
foo<int>();
foo<float>();
#ifdef TEST
foo<char>(); //! Doesn't compile.
#endif
}
With arguments you can use “perfect forwarding” (which isn't all that perfect, really, but usually good enough) via std::forward.

How to reuse function specialization code?

#include <iostream>
using namespace std;
template<typename T>
void fun(const T & val)
{
cout << " T " << endl;
}
template<>
void fun<int>(const int & val)
{
cout << " specialization same code " << val << endl;
}
template<>
void fun<double>(const double& val)
{
cout << " specialization same code " << val << endl;
}
int main()
{
fun( 1 );
fun( 1.0 );
fun( 'c' );
return 0;
}
Question> Is there a way that I can reuse the function specialization code?
For example, assume both 'int and 'double' specialization has the exactly same implementation code. Is there a method I can prevent the code duplication?
http://codepad.org/awGYWiWv
Thank you
As suggested by #0x499602D2 in the comments, create another function and make sure it gets called only for int or double.
template<typename T>
void bar(const T & val)
{
// Make sure this gets called only for int or double.
static_assert(std::is_same<T, int>::value || std::is_same<T, double>::value);
// Do useful stuff with val.
}
template<>
void fun<int>(const int & val)
{
bar(val);
}
template<>
void fun<double>(const double& val)
{
bar(val);
}
To reuse the same code for multiple types of the same kind, you could use std::enable_if (or boost::enable_if if you are not using C++11) with type traits (a nice example is here).
e.g.:
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
fun(const T& val)
{
cout << " floating point specialisation " << val << endl;
}
(function specialisations of this kind work only in C++11, but you can use a struct or class for the same purpose in older C++ versions)
something like this should give you the level of re-use you want:
#include <iostream>
#include <type_traits>
using namespace std;
// will only compile if T is an arithmetic type
template<typename T,
typename std::enable_if<
std::is_arithmetic<T>::value>::type* = nullptr>
void fun(T val)
{
cout << "the square is " << val * val << endl;
}
int main()
{
int x = 10;
double y = 10;
fun(x);
fun(y);
return 0;
}

How to specialize template function with template types

Is it possible to specialize a template function for template types? I don't know if my terminology is correct, so I'll provide a simple sample with what I want to achieve:
#include <vector>
#include <string>
#include <iostream>
template<typename T>
void f()
{
std::cout << "generic" << std::endl;
}
template<>
void f<std::string>()
{
std::cout << "string" << std::endl;
}
template<typename T>
void f<std::vector<T>>()
{
std::cout << "vector" << std::endl;
}
int main()
{
f<double>();
f<std::string>();
f<std::vector<int>>();
return 0;
}
This code doesn't compile. VS2013 gives me
error C2995: 'void f(void)' : function template has already been defined
on this function:
template<typename T>
void f<std::vector<T>>()
{
std::cout << "vector" << std::endl;
}
How may I achieve this behavior? It's very important to have type f(void) signature. Is this code falling into partial specialization for functions(forbidden in C++)?
You can't partially specialize template function, but you can for template class.
So you can forward your implementation to a dedicated class.
Following may help: (https://ideone.com/2V39Ik)
namespace details
{
template <typename T>
struct f_caller
{
static void f() { std::cout << "generic" << std::endl; }
};
template<>
struct f_caller<std::string>
{
static void f() { std::cout << "string" << std::endl; }
};
template<typename T>
struct f_caller<std::vector<T>>
{
static void f() { std::cout << "vector" << std::endl; }
};
}
template<typename T>
void f()
{
details::f_caller<T>::f();
}
Trying to be as close as possible to the original code is:
#include <vector>
#include <string>
#include <iostream>
template<typename T>
struct f {
void operator()()
{
std::cout << "generic" << std::endl;
}
};
template<>
struct f<std::string> {
void operator()()
{
std::cout << "string" << std::endl;
}
};
template<typename T>
struct f<std::vector<T> > {
void operator()()
{
std::cout << "vector" << std::endl;
}
};
int main()
{
f<double>()();
f<std::string>()();
f<std::vector<int> >()();
return 0;
}