Explicit function template specialization - Why? - c++

I keep reading and researching, different posts, c++ books, articles and so far nobody has explained the rational for this construct to me. It makes no sense and its really bugging me. The whole point of a template is to parameterize types to functions (or classes, but i'm talking specifically function template, not class). Why use funny template syntax without the type parameter???
//this seems ridiculous. why would anybody ever use this?
template<> void Swap(int & a , int & b){}
//I would always use this if I needed to take care of a special case, no?
void Swap(int & a , int & b){}
What am I missing? I would really appreciate some insight, and I do understand that function template specialization is not all that useful in practice anyway, but i still want to understand why it was ever invented in the first place. Whoever came up with it must have had a reason which seemed compelling enough at the time.
Thanks.

Great question! Function template specialisation is a bit niche and not generally worth it. You might be a bit confused as to the reason though.
You ask "what's the funny template syntax without a type parameter?" Plenty of use! Specialising templates is very important and useful, and the good old swap example is a classic reason to consider it. A template embodies the idea of a generic algorithm that works with any type, but often if you know a bit about the type you can drop in a much better algorithm, without calling code needing to know that anything different is happening under the hood. Only the compiler knows and it pulls in the best implementation for the real types at the point where the algorithm is instantiated with specific types, so your fast swap happens without the sorting algorithm needing special cases. Specialisation is a key part of making generic programming useful in the real world (or we'd have to use un-generic versions to get the performance we need).
Function template specialisation though is a bit niche, for more obscure reasons. I guess you've read Herb Sutter's summary? So, if you don't want to be caught out, it's a good idea to avoid specialising function templates. (std::swap is an example though of something you have to specialise rather than overload if you want to be ultra-conformant to the standard. We do this widely in our codebase here and it works well in practice, though overloading would probably work well enough too.)
So, please, specialise away all you like. Having class template specialisations, far from being "ridiculous" is often vital, but function template specialisation isn't as useful.

Related

Pertinence of void pointers

Looking through a colleague's code, I see that some of its handles are stored as void pointers.
// Class header
void* hSomeSdk;
// Class implementation
hSomeSdk = new SomeSDK(...);
((SomeSDK*)hSomeSdk)->DoSomeWork();
Now I know that sometimes handles are void pointers because it may be unknown before runtime what will be the actual type of the handle. Or that it can help when we need to share the pointer without revealing its actual structure. But this does not seem to be the case in my situation: it will always be SomeSDK and it is not shared outside the class where it is created. Also the author of this code is gone from the company.
Are there other reasons why it would make sense to have it be a void pointer?
Since this is a member variable, I'm gonna go out on a limb and say your colleague wanted to minimize dependencies. Including the header for SomeSDK is probably undesirable just to define a pointer. The colleague may have had one of two reasons as far as I can see from the code you show:
They just didn't know they can add a forward declarations like class SomeSDK; to allow defining pointers. Some programmers just aren't aware of it.
They couldn't forward declare it. If SomeSDK is not a class, but a type alias (aka typedef), then it's not possible to forward declare it exactly. One can only declare the class it aliases, but that in turn may be an implementation detail that's hard to keep track of. Even the standard library has a similar problem, that is why it provides iosfwd to make forward declaring standard stream types easier.
If the code is peppered with casts of this handle, then the design should have been reworked ages ago. Otherwise, if it's in one place (or a few at most) only, I can see why the people maintaining it could live with it peacefully.
Nope.
If I had to guess, the ex-colleague was unfamiliar with forward declarations and thus didn't know they could still do SomeSDK* in the header without including the entire SomeSDK definition.
Given the constraints you've mentioned, the only thing this pattern achieves is to eliminate some type safety, make the code harder to read/maintain, and generate a Stack Overflow question.
void* were popular and needed back in C. They are convenient in the sense that they can be easily cast to anything. If you need to cast from double* to char*, you have to make a mid cast to void*.
The problem with void* is that they are too flexible: they do not convey intentions of the writer, making them very unsafe especially in big projects.
In Object Oriented Design it is popular to create abstract interface classes (all members are virtual and not implemented) and make pointers to such classes and then instantiate various possible implementation depending on the usage.
However, nowadays, it is more recommended to work with templates (main advantage of C++ over other languages), as those are much faster and enable more compile-time optimization than OOD allowed. Unfortunately, working with templates is still a huge hassle - they have more complicated syntax and it is difficult to convey intentions of the writer to users about restrictions and demands of the template parameters (Concepts TS that solves this problem decently will be available in C++20 - currently there is only SFINAE, a horrible temporary solution from 20 years ago; while Reflection TS, that will greatly enhance generic programming in C++, is unlikely to be available even in C++23).

Why is std::pair<A,B> not the same as std::tuple<A,B>? (Is there really no way?)

Why is std::pair<A,B> not the same as std::tuple<A,B>? It always felt strange to not be able to just substitute one with the other. They are somewhat convertible, but there are limitations.
I know that std::pair<A,B> is required to have the two data members A first and B second, so it can't be just a type alias of std::tuple<A,B>. But my intuition says that we could specialize std::tuple<A,B>, that is a tuple with exactly two elements, to equal the definition of what the standard requires a std::pair to be. And then alias this to std::pair.
I guess this wouldn't be possible as it is too straight-forward to not to be already thought of, yet it wasn't done in g++'s libstdc++ for example (I didn't look at the source code of other libraries). What would the problem of this definition be? Is it "just" that it would break the standard library's binary compatibility?
You've gotta be careful about things like SFINAE and overloading. For example, the code below is currently well-formed but you would make it illegal:
void f(std::pair<int, int>);
void f(std::tuple<int, int>);
Currently, I can disambiguate between pair and tuple through overload resolution, SFINAE, template specialization, etc. These tools would all become incapable of telling them apart if you make them the same thing. This would break existing code.
There might have been an opportunity to introduce it as part of C++11, but there certainly isn't now.
This is purely historical. std::pair exist since C++98 whereas tuple came after and was initially not part of the standard.
Backward compatibility is the biggest burden for C++ evolution, preventing some nice things to be done easily !
I've not tried this and don't have the bandwidth right now to do so. You could try making a specialisation of std::tuple, derived from a sd::pair. Someone please tell me this won't work or is particularly horrible idea. I suspect you'd run into trouble with accessors.

static_cast's argument forwarding

Suppose i don't like the name of static_cast operator and want to wrap it in a function with a different name, say fancy_static_cast but perfectly preserving the semantics. How should i do it? More specifically does static_cast accept it's argument by value or by reference? Or does it depend on the argument expression? Should i provide several overloads or will something like this do the trick?
template <typename To, typename From>
To fancy_static_cast(From&& from)
{
return static_cast<To>(std::forward<From>(from));
}
Suppose i don't like the name of static_cast operator and want to wrap it in a function with a different name, say fancy_static_cast but perfectly preserving the semantics. How should i do it?
You shouldn't.
Instead, you say static_cast when you mean static_cast. Otherwise you will achieve only a lack of maintainability: Readers of your code will at first not recognize the static_cast, and when they look at the function they won't have an idea why the heck you did this and waste brainpower just to realize that you do essentially nothing.
Be clear and crisp with your code. Say what you mean, don't delude the readers (including yourself) by being overly fancy. Don't use misleading namings, instead try to use the parts of the language everybody knows by heart. Give yourself and others as few as possible opportunities to misunderstand what you have written.

How can I make switching between arithmetics easy in C++?

I am making a project that will use mathematic computations a lot. Also I want to be able to simply change the implementation of real numbers. Let's say between float, double, my own implementation and gmplib float types.
So far I thouht of two ways:
I create a class "Number" which will interface with the rest of the program.
I typedef the arithmetic type and write global functions to interface with the rest of the program.
The first choice seems to be more elegant, but the second seems to have less overhead. Is there a third better choice? Also I am worried by the elementary mathematical functions such as sine, cosine, exp... I figured out that to make the switching easy, I should implement them as templates, but my implementations are hopelessly slow.
I am generally new to programming in C++. I was brought up in the comfortable Matlab and Mathematica environments, where I did not have to worry about such things.
You'll want to use templates with constraints to avoid re-implementing things.
For instance, say you want to use sin in your program differently for float and double. You can overload based on type and create specialized templates.
template<class T> T MySin(const T& f) {
return genericSin(f);
}
template<> float MySin<float>(float f) {
return sinf(f);
}
template<> double MySin<double>(double d) {
return sin(d);
}
For functions. The syntax is similar when partially specializing a Math class if you want to go the OO route. This will enable you to call your routines with any type and have the most specialized and most efficient routine called.
Templates are the way I have done this. it makes it easy to specialize what must be specialized, and provides a good way to reuse implementations when it applies to multiple types.
The number type can be done, but it's actually not simple to do right and introduces some restrictions (compared to templates).
Multiple types are just hopelessly complex, if you want something even close to fast, accurate, and simple to maintain. You'd likely end up using templates to implement these correctly if you were to create a global typedef.
Templates provide all the power, control, and flexibility you would need, and they will be faster than the alternatives posted (technically, #2 could be as fast if you resorted to... templates).
a template class like real numbers should work for you. in that you can overload the required functions and if required use template specializations.
in order to improve efficiency use STL algorithms instead of hand written loops.
good luck
Both alternatives are equivalent in terms of encapsulation: There will be a single point in your program where you'll have to change the number type, and this one change will affect your whole program. If presented with those two alternatives, choose the typedef; it is less elegant (=> simpler, and simpler is better) and has the same power.
When you get more comfortable with C++, templating your functions will be a better fit, since the determination of the number type can be made locally instead of globally. With templates, you determine the number type at the instantiation point (most likely the call site), giving much greater flexibility. However, there is a number of pitfalls in templates, and I'd recommend to you that you get a little more experience with C++ first and then start templating.

Should I make my functions as general as possible?

template<class T>
void swap(T &a, T &b)
{
T t;
t = a;
a = b;
b = t;
}
replace
void swap(int &a, int &b)
{
int t;
t = a;
a = b;
b = t;
}
This is the simplest example I could come up with,but there should be many other complicated functions.Should I make all methods I write templated if possible?
Any disadvantages to do this?
thanks.
Genericity has the advantage of being reusable. However, write things generic, only if:
It doesn't take much more time to do that, than do it non-generic
It doesn't complicate the code more than a non-generic solution
You know will benefit from it later
However, know your standard library. The case you presented is already in STL as std::swap.
Also, remember that when writing generically using templates, you can optimize special cases by using template specialization. However, always to it when it's needed for performance, not as you write it.
Also, note that you have the question of run-time and compile-time performance here. Template-based solutions increase compile-time. Inline solutions can but not must decrease run-time.
`Cause "Premature optimization and genericity is the root of all evil". And you can quote me on that -_-.
Reusable code is reusable only if you actually reuse it. so write the function naturally in the first instance. If a bit later you come across a situation where the code could be reused with a little tweak, go back and refactor it, It is at the refactoring stage you should consider writing template functions.
The simplest answer to your question is what many people smarter than myself have been saying for years:
Never write more than the minimum you can get away with.
Make them as generic as you can trivially make them. If it's truly trivial (such as the above example) then it takes no extra work, and might save you some work in the future
The first time you write swap you shouldn't
The second time it might be tempting but sometime you can get away without making the whole thing a mess
The third time it should be clear that you must. However depending on how many places you've used one and two it might be time consuming so the second time should be a good decision
There are disadvantages to using templates all the time. It (can) greatly increase the compilation time of your program and can make compilation errors more difficult to understand.
As taldor said, don't make your functions more generic than they need to be.
You may take a look at the function parameters and the way they are used. If all operations are done through overloaded operators the function may be very generic and a good candidate to become a template. Otherwise, the presence of very specialized class types and functions calls may make generic reusability very problematic and any eventual flexibility should be rather realized through polymorphism.
A few thoughts:
Know the STL. There is std::swap already. Instead of spending your time making everything as generic as possible, spend your time becoming more familiar with the STL.
Don't do it till you need it: "Always implement things when you actually need them, never when you just foresee that you need them."---Ron Jeffries. If you don't actually reuse the code you didn't write reusable code, you wrote unnecessary code. Unnecessary code is expensive to develop, expensive to test, and expensive to maintain. Don't forget opportunity cost!
Keep things simple: "Make everything as simple as possible, but not simpler."---Albert Einstein. This is KISS.