I write a simple code with template and specialization:
#include <iostream>
template <class T>
int HelloFunction(const T& a)
{
std::cout << "Hello: " << a << std::endl;
return 0;
}
template <>
int HelloFunction(const char* & a)
{
std::cout << "Hello: " << a << std::endl;
return 0;
}
int main()
{
HelloFunction(1);
HelloFunction("char");
return 0;
}
I think the char* specialization is correct, but g++ report:
D:\work\test\HelloCpp\main.cpp:11:5:
error: template-id 'HelloFunction<>' for 'int HelloFunction(const char*&)' does not match any template declaration
please help me find the bug.
Function template can be fully specialized and cannot be partially specialized, this is a fact.
That said, the most of the time overloading works just fine and you don't need any specialization at all:
#include <iostream>
template <class T>
int HelloFunction(const T &a) {
std::cout << "Hello: " << a << std::endl;
return 0;
}
int HelloFunction(const char *a) {
std::cout << "Hello: " << a << std::endl;
return 0;
}
int main() {
HelloFunction(1);
HelloFunction("char");
return 0;
}
Non template functions are (let me say) preferred over function templates, thus you can easily got what you pay for in your code with an old plain function.
You can't use the template specialization for function overloading. if this is what you want to do.
Template specialization is meant for specializing the objects and not bare functions. Probably you can change you code something like this to do what you want to do.
template<typename T>
struct ABC {
T type;
ABC(T inType) : type(inType) {}
};
template <class T>
int HelloFunction(ABC<T>& a)
{
std::cout << "Hello: " << a.type << std::endl;
return 0;
}
template <>
int HelloFunction(ABC<const char*> & a)
{
std::cout << "Hello: " << a.type << std::endl;
return 0;
}
int main()
{
HelloFunction(ABC<int>(1));
HelloFunction(ABC<const char*>("char"));
return 0;
}
As you can see from the code above, you use specialization for ABC and using the same in the function HelloFunction
Related
This question continues Non-static data members class deduction
Here are the unnamed argument functions, that I'm using to return std::string representation of the data type
struct Boo {};
struct Foo {};
std::string class2str(const double) { return "Floating"; };
std::string class2str(const int) { return "Fixed Point"; };
std::string class2str(const Foo) { return "Class Foo"; };
std::string class2str(const Boo) { return "Class Boo"; };
int main(int argc, char* argv[])
{
int x_a;
double x_b;
Foo F;
Boo B;
std::cout << "x_a :" << class2str(x_a) << std::endl;
std::cout << "x_b :" << class2str(x_b) << std::endl;
std::cout << "Foo :" << class2str(F) << std::endl;
std::cout << "Boo :" << class2str(B) << std::endl;
};
For type deduction from the non-static member, I am using template:
struct Foo { double A = 33; }
template<typename Class, typename MemType>
std::string class2str(MemType Class::* mData)
{
return class2str(MemType{}); // Use of empty constructor
}
std::cout << "Foo::A :" << class2str(&Foo::A) << std::endl;
But this template requires the creation of an object with an empty constructor, which may simply not be there
struct Boo
{
double A;
Boo() = delete;
Boo(int x) :A(x) {};
};
struct Foo
{
double A = 33;
Boo b{ 0 };
};
// Compilation error: use of deleted function ‘Boo::Boo()’
std::cout << "Boo::b :" << class2str(&Foo::b) << std::endl;
How to implement this functionality, but without calling an empty constructor?
See online demo: https://onlinegdb.com/lpc5o8pUKy
(As I started writing the answer there was no answer to the question, but as I was about to post it I saw #Jarod42's answer which already show the tag dispatch approach. Posting this answer nonetheless as it uses a slightly different approach of full specializations of a deleted primary template, instead of non-template overloads)
You can use tag dispatch to delegate calls:
#include <iostream>
struct Boo {
double A;
Boo() = delete;
Boo(int x) : A(x){};
};
struct Foo {
double A = 33;
Boo b{0};
};
namespace detail {
template <typename T> struct Tag {};
template <typename T> std::string class2str_impl(Tag<T>) = delete;
template <> std::string class2str_impl(Tag<double>) { return "Floating"; };
template <> std::string class2str_impl(Tag<int>) { return "Fixed Point"; };
template <> std::string class2str_impl(Tag<Foo>) { return "Class Foo"; };
template <> std::string class2str_impl(Tag<Boo>) { return "Class Boo"; };
} // namespace detail
template <typename T> std::string class2str(T) {
return class2str_impl(detail::Tag<T>{});
}
template <typename Class, typename MemType>
std::string class2str(MemType Class::*) {
return class2str_impl(detail::Tag<MemType>{});
}
int main() {
int x_a{42};
double x_b{4.2};
Foo F{};
Boo B{x_a};
std::cout << "x_a :" << class2str(x_a) << std::endl;
std::cout << "x_b :" << class2str(x_b) << std::endl;
std::cout << "Foo :" << class2str(F) << std::endl;
std::cout << "Boo :" << class2str(B) << std::endl;
std::cout << "Boo::b :" << class2str(&Foo::b) << std::endl;
};
where the primary template of class2str_impl may either be deleted (as above), or implement a custom message that a given type does not have a mapped string.
All your overloads currently take object. You might take type instead, or object which hold type:
template <typename T> struct Tag{};
std::string class2str(Tag<double>){ return "Floating";};
std::string class2str(Tag<int>){ return "Fixed Point";};
std::string class2str(Tag<Foo>){ return "Class Foo";};
std::string class2str(Tag<Boo>){ return "Class Boo";};
template<typename Class, typename MemType>
std::string class2str(Tag<MemType Class::*>)
{
return class2str(Tag<MemType> {});
}
With usage:
int main(int argc, char *argv[]) {
int x_a;
double x_b;
Foo F;
Boo B;
std::cout<< "x_a :" << class2str(Tag<decltype(x_a)>{}) <<std::endl;
std::cout<< "x_b :" << class2str(Tag<decltype(x_b)>{}) <<std::endl;
std::cout<< "Foo :" << class2str(Tag<decltype(F)>{}) <<std::endl;
std::cout<< "Boo :" << class2str(Tag<decltype(B)>{}) <<std::endl;
// or
std::cout<< "int :" << class2str(Tag<int>{}) <<std::endl;
};
Different from the tag dispatch and the specialization techniques talked in the other answers, here is a different approach using c++17's constexpr if.
First, we find the type of the member from the member pointer using a trait (mem_type)
Secondly, we write an internal helper function (i.e. helper::class2str()), which uses the compiled time type checking and discard the false branch(i.e. if constexpr), so that we correctly return the data type representation as const char* literals (because we can make the function constexpr)!
Lastly, we will have the main class2str() which actually check the template argument type is a member pointer or not, and do branches as per again using if constexpr. If the template type is a member pointer, we get the member type using the trait mem_type and pass it to the helper::class2str().
#include <type_traits> // std::is_same_v, std::is_member_pointer_v
// trait to get the member type
template<typename Class> struct mem_type {};
template<typename MemType, typename Class> struct mem_type<MemType Class::*> {
using type = MemType;
};
// alias for mem_type<T>
template<typename Type> using mem_type_t = typename mem_type<Type>::type;
namespace helper
{
template<typename Type> constexpr auto class2str() noexcept
{
if constexpr (std::is_same_v<Type, int>) return "Fixed Point";
else if constexpr (std::is_same_v<Type, double>) return "Floating";
else if constexpr (std::is_same_v<Type, Boo>) return "Class Boo";
else if constexpr (std::is_same_v<Type, Foo>) return "Class Foo";
}
}
template<typename Type>
std::string class2str()
{
if constexpr (std::is_member_pointer_v<Type>)
return helper::class2str<mem_type_t<Type>>();
else
return helper::class2str<Type>();
}
Now you can use it like:
std::cout << "x_a :" << class2str<int>() << '\n';
std::cout << "x_b :" << class2str<double>() << '\n';
std::cout << "Boo::b :" << class2str<decltype(&Boo::A)>() << '\n';
std::cout << "Foo::b :" << class2str<decltype(&Foo::b)>() << '\n';
Here is (the complete demo)
Make a class template and specialzie it for various types:
template <typename T> struct TypeNameHelper {};
template <> struct TypeNameHelper<int> { static constexpr std::string_view name = "Integer"; };
template <> struct TypeNameHelper<float> { static constexpr std::string_view name = "Real"; };
I would also add a variable template for a shorter syntax and to preprocess the type if needed:
template <typename T>
inline constexpr std::string_view TypeName = TypeNameHelper<std::remove_cvref_t<T>>::name;
Then you can do:
std::cout << TypeName<int> << '\n';
One idea could be to use the function arguments to call function overloads that only requires a template parameter:
struct Boo {
double A;
Boo()= delete;
Boo(int x) :A(x){};
};
struct Foo {
double A = 33;
Boo b{0};
};
#include <type_traits>
#include <utility>
template<class T> std::string class2str(); // primary
// specializations
template<> std::string class2str<double>(){ return "Floating"; };
template<> std::string class2str<int>(){ return "Fixed Point"; };
template<> std::string class2str<Foo>(){ return "Class Foo"; };
template<> std::string class2str<Boo>(){ return "Class Boo"; };
// taking by argument
template<class T>
std::string class2str(const T&) {
return class2str<std::remove_cv_t<std::remove_reference_t<T>>>();
}
// class member by argument
template<typename Class, typename MemType>
std::string class2str(MemType Class::*) {
return class2str<std::remove_cv_t<std::remove_reference_t<MemType>>>();
}
int main() {
int x_a;
double x_b;
Foo F;
Boo B{1};
std::cout<< "x_a :" << class2str(x_a) <<std::endl;
std::cout<< "x_b :" << class2str(x_b) <<std::endl;
std::cout<< "Foo :" << class2str(F) <<std::endl;
std::cout<< "Boo :" << class2str(B) <<std::endl;
std::cout<< "Foo::A :" << class2str(&Foo::A) <<std::endl;
std::cout<< "Foo::b :" << class2str(&Foo::b) <<std::endl;
std::cout<< "Boo::A :" << class2str(&Boo::A) <<std::endl;
};
Output:
x_a :Fixed Point
x_b :Floating
Foo :Class Foo
Boo :Class Boo
Foo::A :Floating
Foo::b :Class Boo
Boo::A :Floating
A common trick used in the standard library is to use declval.
It's sort of designed for this exact use-case.
Or simpler still
template<typename Class, typename MemType>
std::string class2str(MemType Class::*){
return class2str(*reinterpret_cast<MemType*>(0)); // Never use the value, it's null
}
Is there a way to let the compiler distinguish whether the passed variable is a reference or not, without explicitly specifying it using e.g. <int &>? The following example displays '1', whereas I expected a '2':
template <typename Type>
void fun(Type)
{
cout << 1 << '\n';
}
template <typename Type>
void fun(Type &)
{
cout << 2 << '\n';
}
int main()
{
int x = 0;
int &ref = x;
fun(ref);
}
I also tried to use std::ref, but I don't get it to work.
template <typename Type, typename = std::enable_if_t<!std::is_reference<Type>::value>>
void fun(Type)
{
std::cout << 1 << '\n';
}
template <typename Type, typename = std::enable_if_t<std::is_reference<Type>::value>>
void fun(Type &)
{
std::cout << 2 << '\n';
}
int main() {
int x = 0;
int &ref = x;
fun<int&>(ref); // Call the one that you want, and don't leave the compiler decide which one you meant
return EXIT_SUCCESS;
}
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;
}
I was studying about template specialization but unable to understand mixed class and int.
The following code fails to compile click to compile. Can someone suggest the right way here. I wish to specialize for int class. the second template m should be defined as 0 but how to specify that.
#include <iostream>
using namespace std;
template <class T,int m>
void fun(T a )
{
cout << "The main template fun(): " << a << " " << m << endl;
}
template<>
void fun(int a)
{
cout << "Specialized Template for int type: " << a << endl;
}
int main()
{
fun<char,10>('a');
fun<int,20>(10);
fun<float,12>(10.14);
}
The error is:
prog.cpp:11:6: error: template-id 'fun<>' for 'void fun(int)' does not match any template declaration
void fun(int a)
^
I suggest to change order of parameter to let T be deduced, then simply use overload:
template <int m, class T>
void fun(T a )
{
cout << "The main template fun(): " << a << " " << m << endl;
}
template <int m>
void fun(int a)
{
cout << "Template for int type: " << a << endl;
}
With usage:
fun<10>('a');
fun<20>(10);
fun<12, float>(10.14); // or simply fun<12>(10.14f);
I assume that what you're trying to do is to specialise the template so that any call of the form
fun<int, N>(...);
Calls the specialisation?
This would require a partial specialisation of fun() for int, but the C++ language forbids partially specialising function templates. However, we can partially specialise class templates just fine. So one approach to do what you want would be to implement your fun() function using function objects, like so:
// General case
template <typename T, int N>
struct do_fun {
void operator()(T a) {
cout << "The main template fun(): " << a << " " << N << endl;
}
};
// Specialisation for int
template <int N>
struct do_fun<int, N> {
void operator()(int a) {
cout << "Specialized Template for int type: " << a << endl;
}
};
You can then supply a wrapper function template that uses the function objects:
template <typename T, int N>
void fun(T a) {
do_fun<T, N>{}(a);
}
Coliru example
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.