Template Specialization or Function Overloading - c++

I know there are other questions like this but they are not very clear.
Now I feel as though this is a stupid question because I'm sure I already have the answer but let me ask anyways.
So I basically have a function that takes in a string and then based on the appropriate variable type it converts it like so:
template<class T>
void ConvertValue(std::string str, T &variable)
{
variable = static_cast<T>(str);
}
so this seems to be fine correct? But the thing is that you cannot convert a string to say an int or a float so therefore I would have to do template specialization for ints and floats and for other types it can't convert to so what I'm asking is should I have something like this:
void ConvertValue(std::string str, int &variable) { variable = atoi(str.c_str()); }
void ConvertValue(std::string str, float &variable) { ... }
void ConvertValue(std::string str, double &variable) { ... }
void ConvertValue(std::string str, std::vector<int> &variable) { ... }
..etc
or should I use template specialization? Which one would make more sense? I'm leaning towards function overloading because majority of the types are going to have their own conversion function so since they slightly differ function overloading makes logical sense to me but I don't know if I'm missing something.
Should I stick with function overloading? Or switch to template specialization?

If the internals of the function are going to have to be different for each type and potentially include type checks, it is simpler and cleaner to just have multiple functions.
If on the other hand you had a bunch of classes with a toString() method for conversion. Then you would use a template because the internals would always be the same.

I would use std::istringstream:
template <typename T>
T ConvertValue(const std::string& str)
{
std::istringstream iss(str);
T ret;
if (!(iss >> ret))
{
throw std::bad_cast("Failed!");
}
return ret;
}

This should be the answer to your questions :
how to get typeof variable in C++
and yes it should be template specialization.

Short answer :
You are right. Function Overloading makes more sense. Function base template specialization does not overload.
Long Answer
function base template specializations are class 2 citizen, functions are first class citizen.
If you write an overloaded function nobody can write anything overloading or hiding your code without getting a compiler error. If you write a function base template specialization anybody can overload it with a function overload matching that function base template specialization signature. (yes, the programmer writing the specialization will be pissed of at your function, but will have to live with that).
If you want a better question for a better answer, read Why Not Specialize Function Templates? : http://www.gotw.ca/publications/mill17.htm

Related

Why use template specializations?

I wonder why template specializations make sense?
Aren't the following things equivalent?
Template specialization:
template <typename T>
void f(T t) {
something(t);
}
template <>
void f<int>(int t) {
somethingelse(t);
}
Non-template function instead of specialization:
void f(int t) {
somethingelse(t);
}
I believe these are the same because the non-template function will always be preferred.
This is the answer I came up with:
It's different if the template parameter is not a parameter of the function being defined:
template <typename T>
void f() {
T t;
something(t);
}
template <>
void f<int>() {
int t;
somethingelse(t);
}
In this case defining:
void f() {
int t;
somethingelse(t);
}
would make all the template versions unuseable.
Maybe somebody else has better ideas. :)
The question boils down to determining when the specialization will be used that the overload cannot. There are different situations where this is the case although they are uncommon enough, and it is simple enough to make mistakes that the general recommendation is to prefer overloads to specializations.
When the caller explicitly requests the use of a template. In the code example you provide if the call is f<int>(42) or even f<42>(), then the overload will not be used.
When you cannot provide the required overloads, or the overload cannot be resolved at the place of call. For example if the type is not one of the function arguments (it is either not present in the signature at all or only in the return type:
template
T f();
In this case, you cannot provide overloads int f(); and double f(); but you can provide as many template specializations as you need, and it will be up to the user to force the selection of one or the other. Note that this could be considered a subcase of the previous case: because the template arguments take no part in the function arguments, the user needs to provide the template arguments, so the call is explicitly to a template.
When you want to place special constraints on the combination of arguments and inhibit implicit conversions:
template
void f( T, T ); // Both argument must be the same type
Because template argument deduction only perform perfect matches, this template can only be used when both arguments are of the exact same type, if you add an overload void f(int,int) that overload can be used with any combination of types that are implicitly convertible to int, like f( 5, 3.0 ), but the specialization won't.
In general, for most cases, none of the cases above really apply, so an overload should be preferred.
There might be more, but those are the ones I can recall off the top of my head
The way you declare the function does matter if you insist on calling it like f<int>(42). This will find the specialization, but not the overload.
If the call always looks like f(42), either alternative will work.
Function template specialization is deprecated in favor of function overloads with one exception: you are allowed to add a function template specialization to the std namespace, you aren't allowed to add a new function. So, if you need to supply a specific version for something in the std namespace, you have to use template specialization. For instance, to support creating an unordered_map with a user-defined class as the key you have to specialize std::hash for your class.

What is angle brackets for argument values, and what is it used for? [duplicate]

This question already has answers here:
Reason for using non-type template parameter instead of regular parameter?
(6 answers)
Closed 4 years ago.
I am used to angle brackets being used to specify a type, as a parameter:
vector<int> vecOfInts ;
But in rapidjson, there is code like this:
document.Parse<0>(json) ;
The document.Parse method's signature is:
template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
GenericStringStream<Encoding> s(str);
return ParseStream<parseFlags>(s);
}
I didn't know you could pass a value inside angle brackets - thought angle brackets were used for typenames alone.
What is the code here doing, and why is he passing a value in the angle brackets?
Is this a good idea? When?
There are two different factors going on here.
First, it's possible to define templates that are parameterized over things other than just types. For example, here's a simple array type:
template <typename T, size_t N> struct Array {
T arr[N];
};
We can use this like
Array<int, 137> myArray;
We know that vector<int> and vector<double> are different types. But now we must also point out that Array<int,137> and Array<int,136> are different types.
Second, when using templates, the compiler has to be able to figure out a value for all of the template arguments. When you're using template classes, this is why you typically specify all the template arguments. You don't say vector x, for example, but instead say something like vector<double> x. When using template functions, most of the time the compiler can figure out the arguments. For example, to use std::sort, you just say something like
std::sort(v.begin(), v.end());
However, you could also write
std::sort<vector<int>::iterator>(v.begin(), v.end());
to be more explicit. But sometimes, you have a template function for which not all the arguments can be figured out. In your example, we have this:
template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
GenericStringStream<Encoding> s(str);
return ParseStream<parseFlags>(s);
}
Notice that the parseFlags template parameter can't be deduced from just the arguments of the function. As a result, to call the function, you must specify the template parameter, since otherwise the compiler can't figure it out. That's why you'd write something like
Parse<0>(myString);
Here, the 0 is a template argument (resolved at compile-time), and myString is the actual argument (resolved at run-time).
You can actually have methods that combine a bit of type inference and a bit of explicit type parameters. For example, in Boost, there's a function lexical_cast that can do conversions to and from string types. The function signature to convert from a non-string type to a string type is
template <typename Target, typename Source>
Target lexical_cast(const Source& arg);
Here, if you call lexical_cast, the compiler can figure out what Source is, but it can't deduce Target without some hints. To use lexical_cast, therefore, you'd write something like
std::string myString = boost::lexical_cast<std::string>(toConvertToString);
More generally, the compiler says that you have to specify some number of template arguments (optionally 0), and it will try to deduce the rest. If it can, great! If not, it's a compile-time error. Using this, if you'd like, you could write a function like
template <int IntArgument, typename TypeArgment>
void DoSomething(const TypeArgument& t) {
/* ... */
}
To call this function, you'd have to invoke it like this:
DoSomething<intArg>(otherArg);
Here, this works because you have to explicitly tell the compiler what IntArgument is, but then the compiler can deduce TypeArgument from the type of the argument to DoSomething.
Hope this helps!

Syntax for specializing function templates in C++

Suppose I have a function template where the type parameter is used as a return type only:
template <typename T>
T foo()
{
return whatever;
}
Then what is the correct syntax to specialize that function template? Both of the following seem to work:
template <>
std::string foo()
{
return whatever;
}
template <>
std::string foo<std::string>()
{
return whatever;
}
Is there any difference between the two? If not, what is the idiomatic way?
The compiler will deduce the correct template specialization based on informations provided (here, the function return type).
So these syntaxes have exactly the same behaviour, one being more explicit than the other.
In most case, there is no difference between the two.
If you overload several template functions, the second form may be needed to remove an ambiguity about which overload you mean to specialize (you probably have other problems if you are in this situation, for instance you'll also need to be explicit at call places).

Template specialization for C-style string

I'm having difficulty getting the correct syntax for a template specialisation which accepts a regular c-style string. For example
namespace RubyUtils
{
template<class T> VALUE toValue(const T& v);
};
template<> VALUE toValue(char const* & v)
{
return toValue<string>(v);
}
and then at the call site
return RubyUtils::toValue("Life the universe and everything");
gives an error
unresolved external symbol "unsigned long __cdecl RubyUtils::toValue<char const [33]>(char const (&)[33])"
how should I structure the specialisation to enable passing in c-style strings?
UPDATE: Fixed the template specialisation to have correct syntax template => template<>
I think that the problem you're encountering is probably related to the fact that you've defined two templates - one inside of the namespace, and one out. The error is likely due to this confusion.
But more importantly, as a general rule, you do not want to specialize function templates. Template specialization for function has lots of funky rules associated with it that almost universally result in the wrong thing getting called. Rather, just use regular function overloading:
namespace RubyUtils
{
template<class T> VALUE toValue(const T& v);
VALUE toValue(char const* v)
{
return toValue<string>(v);
}
};
The way function overloading works, calling the toValue function with a C-style string will cause the non-template toValue to get selected ahead of the toValue template, essentially doing the specialization for you. More generally, with function templates, prefer using overloading to specialization. It's just safer.

C++ - What is the purpose of function template specialization? When to use it?

Learning C++, came upon function templates. The chapter mentioned template specialization.
template <> void foo<int>(int);
void foo( int );
Why specialize when you can use the second? I thought templates were suppose to generalize. What's the point of specializing a function for a specific data type when you can just use a regular function?
Obviously, template specialization exists for a reason. When should it be used? I read Sutter's "Why not Specialize..." article but I need more of a layman's version since I'm just learning this stuff.
The main difference is that in the first case you are providing the compiler with an implementation for the particular type, while in the second you are providing an unrelated non-templated function.
If you always let the compiler infer the types, non-templated functions will be preferred by the compiler over a template, and the compiler will call the free function instead of the template, so providing a non-templated function that matches the arguments will have the same effect of specializations in most cases.
On the other hand, if at any place you provide the template argument (instead of letting the compiler infer), then it will just call the generic template and probably produce unexpected results:
template <typename T> void f(T) {
std::cout << "generic" << std::endl;
}
void f(int) {
std::cout << "f(int)" << std::endl;
}
int main() {
int x = 0;
double d = 0.0;
f(d); // generic
f(x); // f(int)
f<int>(x); // generic !! maybe not what you want
f<int>(d); // generic (same as above)
}
If you had provided an specialization for int of the template, the last two calls would call that specialization and not the generic template.
I personally can see no benefit from specializing a function template. Overloading it by either a different function template or a non-template function is arguably superior because its handling is more intuitive and it's overall more powerful (effectively by overloading the template, you have a partial specialization of the template, even though technically it's called partial ordering).
Herb Sutter has written an article Why not specialize function templates? where he discourages specializing function templates in favour of either overloading them or writing them so that they just forward to a class template's static function and specializing the class template instead.
You can use specialization when you know for a specific class the generic method could be efficient.
template<typename T>
void MySwap(T& lhs, T& rhs)
{
T tmp(lhs);
lhs = rhs;
rhs = tmp;
}
Now for vectors my swap will work, but is not very effecient. But I also know that std::vector implements its own swap() method.
template<>
void MySwap(std::vector<int>& lhs,std::vector<int>& rhs)
{
lhs.swap(rhs);
}
Please don;t compare to std::swap which is a lot more complex and better written. This is just an example to show that a generic version of MySwap() will work but is may not always be efficient. As a result I have shown how it can be made more efficient with a very specific template specialization.
We can also of course use overloading to achieve the same effect.
void MySwap(std::vector<int>& lhs,std::vector<int>& rhs)
{
lhs.swap(rhs);
}
So the question if why use template specialization (if one can use overloading). Why indeed. A non template function will always be chosen over a template function. So template specialization rules are not even invoked (which makes life a lot simpler as those rules are bizarre if you are not a lawyer as well as a computer programmer). So let me thing a second. No can't think of a good reason.
I find it very important. You can use this as you would use a virtual method. There would be no point in virtual methods unless some of them were specialized. I have used it a lot to differentiate between simple types (int,short,float) and objects, object pointers and object references.
An example would be serialize/unserialize methods that would handle objects by calling the objects serialize/unserialize method, while simple types should be written directly to a stream.
One case for template specialization which is not possible with overloading is for template meta-programming. The following is real code from a library that provides some of it services at compile time.
namespace internal{namespace os{
template <class Os> std::ostream& get();
struct stdout{};
struct stderr{};
template <> inline std::ostream& get<stdout>() { return std::cout; }
template <> inline std::ostream& get<stderr>() { return std::cerr; }
}}
// define a specialization for os::get()
#define DEFINE_FILE(ofs_name,filename)\
namespace internal{namespace os{ \
struct ofs_name{ \
std::ofstream ofs; \
ofs_name(){ ofs.open(filename);} \
~ofs_name(){ ofs.close(); delete this; } \
}; \
template <> inline std::ostream& get<ofs_name>(){ return (new ofs_name())->ofs; } \
}} \
using internal::os::ofs_name;
Multiple overloads on the same name do similar things. Specializations do the exact same thing, but on different types. Overloads have the same name, but may be defined in different scopes. A template is declared in only one scope, and the location of a specialization declaration is insignificant (although it must be at the scope of the enclosing namespace).
For example, if you extend std::swap to support your type, you must do so by specialization, because the function is named std::swap, not simply swap, and the functions in <algorithm> would be quite right to specifically call it as ::std::swap( a, b );. Likewise for any name that might be aliased across namespaces: calling a function may get "harder" once you qualify the name.
The scoping issue is confused further by argument-dependent lookup. Often an overload may be found because it is defined in proximity to the type of one of its arguments. (For example, as a static member function.) This is completely different from how the template specialization would be found, which is by simply looking up the template name, and then looking up the explicit specialization once the template has been chosen as the target of the call.
The rules of ADL are the most confusing part of the standard, so I prefer explicit specialization on the priciple of avoiding reliance on it.