Differences between template specialization and overloading for functions? - c++

So, I know that there is a difference between these two tidbits of code:
template <typename T>
T inc(const T& t)
{
return t + 1;
}
template <>
int inc(const int& t)
{
return t + 1;
}
and
template <typename T>
T inc(const T& t)
{
return t + 1;
}
int inc(const int& t)
{
return t + 1;
}
I am confused as to what the functional differences between these two are. Can someone show some situations where these snippits act differently from each other?

I can only think of a few differences - here are some examples that don't necessarily cause harm (i think). I'm omitting definitions to keep it terse
template <typename T> T inc(const T& t);
namespace G { using ::inc; }
template <> int inc(const int& t);
namespace G { void f() { G::inc(10); } } // uses explicit specialization
// --- against ---
template <typename T> T inc(const T& t);
namespace G { using ::inc; }
int inc(const int& t);
namespace G { void f() { G::inc(10); } } // uses template
That is because specializations are not found by name lookup, but by argument matching, so a using declaration will automatically consider a later introduced specialization.
Then, you of course cannot partially specialize function templates. Overloading however accomplishes something very similar by partial ordering (using different types now, to make my point)
template <typename T> void f(T t); // called for non-pointers
template <typename T> void f(T *t); // called for pointers.
int a;
void e() {
f(a); // calls the non-pointer version
f(&a); // calls the pointer version
}
That wouldn't be possible with function template explicit specialization. Another example is when references are involved, which causes template argument deduction to look for an exact match of the types involved (modulo base/derived class relationships and constness):
template<typename T> void f(T const &);
template<> void f(int * const &);
template<typename T> void g(T const &);
void g(int * const &);
int a[5];
void e() {
// calls the primary template, not the explicit specialization
// because `T` is `int[5]`, not `int *`
f(a);
// calls the function, not the template, because the function is an
// exact match too (pointer conversion isn't costly enough), and it's
// preferred.
g(a);
}
I recommend you to always use overloading, because it's richer (allows something like partial specialization would allow), and in addition you can place function in whatever namespace you want (although then it's not strictly overloading anymore). For example, instead of having to specialize std::swap in the std:: namespace, you can place your swap overload in your own namespace and make it callable by ADL.
Whatever you do, never mix specialization and overloading, it will be a hell of a mess like this article points out. The Standard has a lovely paragraph about it
The placement of explicit specialization declarations for function templates, class templates, member functions of class templates, static data members of class templates, member classes of class templates, member class templates of class templates, member function templates of class templates, member functions of member templates of class templates, member functions of member templates of non-template classes, member function templates of member classes of class templates, etc., and the placement of partial specialization declarations of class templates, member class templates of non-template classes, member class templates of class templates, etc., can affect whether a program is well-formed according to the relative positioning of the explicit specialization declarations and their points of instantiation in the translation unit as specified above and below. When writing a specialization, be careful about its location; or to make it compile will be such a trial as to kindle its self-immolation.

Template specialization is more generic than just overloading. You can specialize things like classes rather than just simple functions. Overloading only applies to functions.
UPDATE: To clarify more per AraK's comment, you are really comparing apples and oranges here. Function overloading is used to introduce the ability to have different functions share a single name, if they have different signatures. Template specialization is used to define a specific code snippet for a specific type parameter. You can't have a template specialization if you don't have a template. If you remove the first piece of code that declares the generic template, you'll receive a compile time error if you try to use template specialization.
So, the goal of template specialization is pretty different from a function overload. They just happen to behave similarly in your example while they are fundamentally different.
If you provide an overload, you are declaring an independent method that happens to have the same name. You are not preventing the template to be used with the specific type parameter. To demonstrate this fact, try:
template <typename T>
T inc(const T& t)
{
return t + 1;
}
int inc(const int& t)
{
return t + 42;
}
#include <iostream>
int main() {
int x = 0;
x = inc<int>(x);
std::cout << "Template: " << x << std::endl; // prints 1.
x = 0;
x = inc(x);
std::cout << "Overload: " << x << std::endl; // prints 42.
}
As you can see, in this example, there are two distinct inc functions for int values: inc(const int&) and inc<int>(const int&). You couldn't expand the generic template using int if you had used template specialization.

One such example:
#include <cstdio>
template <class T>
void foo(T )
{
puts("T");
}
//template <>
void foo(int*)
{
puts("int*");
}
template <class T>
void foo(T*)
{
puts("T*");
}
int main()
{
int* a;
foo(a);
}
It is actually suggested that you use non-template overloads for functions and leave specialization for classes. It is discussed at greater length in Why Not Specialize Function Templates?

AFAIK there is no functional difference. All I can add is that if you have both a template function specialisation and an ordinary function defined then there is no overload ambiguity as the ordinary function is favoured.

Just to elaborate on the first point mentioned by litb in his answer. Specializations are only checked once overload resolution has actually selected a primary template. The result can lead to some surprises where a function is overloaded and has explicit specializations:
template <typename T> void foo (T); // Primary #1
template <> void foo<int*> (int*); // Specialization of #1
template <typename T> void foo (T*); // Primary #2
void bar (int * i)
{
foo(i);
}
When choosing which function to call, the following steps take place:
Name lookup finds both primary templates.
Each template is specialized and overload resolution attempts to select a best function based on conversions between the arguments and parameters.
In thise case, there is no difference in the quality of the conversions.
Partial ordering rules are then used to select the most specialized template. In this case that is the second parimary "foo(T*)".
Only after these steps, when the best function has been selected will explicit specializations of the selected function be considered. (In this case primary #2 has none so none are considered).
The only way to call the above explicit specialization here, is to actually use explicit template arguments in the call:
void bar (int * i)
{
foo<int*> (i); // expliit template argument forces use of primary #1
}
A good rule of thumb is to try to avoid having overloads that are also explicily specialized, as the resulting rules are pretty complex.

Related

How do I add a template specialization when for a generic method on a generic class when the two types are equal?

I'm trying to add in a specialization where the generic type of method and class agree, but I haven't been able to figure out exactly how to specify the template instantiation (if it is even possible).
My best guess would be something like the following (though it obviously doesn't compile):
template<typename ClassT>
class Foo
{
public:
ClassT x;
template<typename MethodT>
void Bar(MethodT arg)
{
}
};
template<typename T>
template<>
void Foo<T>::Bar(T arg)
{
x = arg;
}
As is usually the case when considering function template specialization, an overload can handle it:
template<typename MethodT>
void Bar(MethodT arg)
{
}
void Bar(ClassT arg)
{
x = arg;
}
When you call Bar, one of the candidates will be a function template specialization and one won't. Think of the class template as stamping out real, concrete member functions where possible when it's instantiated. There's a rule pretty late in overload resolution to prefer the one that isn't a function template specialization if it's a tie up to that point.
What you end up with is the second overload being called when there's an "exact match" in types (which allows for a difference in top-level const). If exact matches are too narrow, you can restrict the first overload to widen the second:
// Allow the other overload to win in cases like Foo<int>{}.Bar(0.0).
// std::enable_if works as well before C++20.
template<typename MethodT>
void Bar(MethodT arg) requires (not std::convertible_to<MethodT, ClassT>)
{
}
As discussed in the comments, it's not possible to do this with template specialization. However, something similar can be accomplished by using std::enable_if_t and
template<typename ClassT>
class Foo
{
public:
ClassT x;
template<typename MethodT,
typename = std::enable_if_t<!std::is_same<ClassT, MethodT>::value>>
void Bar(MethodT arg)
{
}
void Bar(ClassT arg)
{
x = arg;
}
};
std::enable_if_t will only return a valid type when the input type arg is true. Therefore, the template substitution will fail when MethodT and ClassT are the same type, but the non-template overload will not fail. The template substitution failure is ok under SFINAE.

Alternative to using namespace as template parameter

I know I cannot use a namespace as a template parameter. However, I'm trying to achieve behavior similar to this:
template <typename T>
void foo(T::X* x)
{
T::bar(x);
}
Except T is a namespace rather than a struct or a class. What is the best way to achieve the most similar result to what I am expecting?
Except T is a namespace rather than a struct or a class. What is the best way to achieve the most similar result to what I am expecting?
Don't mention T at all.
template <typename X>
void foo(X* x)
{
bar(x);
}
ADL will always pick up on overloads from the namespace where X is defined. Let the mechanism do its work.
Now, if you are asking how to make the compiler favor functions found by ADL, it's all about manipulating overload resolution. We can do that by limiting what is picked up by regular unqualified name lookup:
namespace foo_detail {
void bar(...);
template<typename X>
void foo_impl(X* x) {
bar(x);
}
}
template <typename X>
void foo(X* x)
{
foo_detail::foo_impl(x);
}
When the call in foo_detail::foo_impl is trying to resolve bar, the first phase in two-phase lookup will pickup the C variable argument function. Now lookup stops, no further enclosing namespaces will be looked in. Which means that only ADL can offer more candidates. And due to how overload resolution works, a C-style variable argument function like we added will be a worse match than anything ADL will find.
Here's a live example for all of this at work.
Namespace can't be a template parameter.
The only possible template parameters are:
types
and values which are: Template parameters and template arguments - cppreference.com
std::nullptr_t (since C++11);
an integral type;
a pointer type (to object or to function);
a pointer to member type (to member object or to member function);
an enumeration type.
So if you want change bar version depending on namespace it can't be done like you proposed.
It can be achieved if bar is enclosed in class as a static function. In such case you can use your template, then that class becomes template parameter.
So your code can look lie this:
class Variant1 {
public:
typedef int* argType;
static void bar(argType i) {
std::cout << (*i + 1);
}
};
class Variant2 {
public:
typedef size_t* argType;
static void bar(argType i) {
std::cout << (*i - 1);
}
};
template <typename T>
void foo(typename T::argType x)
{
T::bar(x);
}
//usage
size_t a = 1;
int x = 1;
foo<Variant1>(&a);
foo<Variant2>(&b);

Why is the return type of C++ function template instantiations included in the mangled function name?

The Itanium ABI specifies that, with a couple uninteresting exceptions, the return type is included in the mangled names of template instantions but not non-templates.
Why is this? In what case could you have two function template instantiations where the linker needs to distinguish them because it is not indicative of a one-definition-rule violation or similar?
As an example of what I mean:
class ReturnType {};
class ParamType {};
template <typename T>
ReturnType foo(T p) {
return ReturnType();
};
template ReturnType foo<ParamType>(ParamType);
ReturnType bar(ParamType p) {
return ReturnType();
}
Then the resulting object file has manglings:
ReturnType foo<ParamType>(ParamType)
=> _Z3fooI9ParamTypeE10ReturnTypeT_
^^^^^^^^^^^^
ReturnType bar(ParamType)
=> _Z3bar9ParamType
Why does foo need ReturnType mangled but bar doesn't?
(I am presuming there is a reason and it's not just an arbitrary choice.)
Maybe because, as opposed to normal functions, a function templates signature contains the return type? §1.3:
1.3.17 signature <function> name, parameter type list (8.3.5), and enclosing namespace (if any) [ Note: Signatures are used as a
basis for name mangling and linking. — end note ]
1.3.18 signature <function template> name, parameter type list (8.3.5), enclosing namespace (if any), return
type, and template parameter list
Consider that we can have two entirely distinct function template overloads that only differ in their return type, if written thusly:
template <int>
char foo();
template <int>
int foo();
If name mangling wouldn't consider the return type, linking those templates would prove difficult, since foo<0> does not uniquely name one specialization. Still, one specialization can be addressed using overload resolution (without arguments):
int (*funptr)() = foo<0>;
On the other hand, including the return type is not necessary for ordinary functions, as these cannot be overloaded on their return type - i.e. their signature does not include the return type.
Template functions may be overloaded by return type alone, unlike regular functions.
template <typename T> int f() { return 1; }
template <typename T> long f() { return 2; }
int main() {
int (&f1) () = f<void>;
long (&f2) () = f<void>;
return f1() == f2();
}
Here, assuming a non-optimising compiler, the generated assembly will contain two functions f<void>(), but they can't share the same mangled name, or there would be no way for the generated assembly for main to specify which of the instantiations it refers to.
Typically, if you have an overloaded template function, only one of the definitions will be used for a particular template argument, so this is uncommon, but in the comments on Columbo's answer, dyp came up with the basic idea for how this might actually be useful. In Can addressof() be implemented as constexpr function?, I came up with
template <bool>
struct addressof_impl;
template <>
struct addressof_impl<false> {
template <typename T>
static constexpr T *impl(T &t) {
return &t;
}
};
template <>
struct addressof_impl<true> {
template <typename T>
static /* not constexpr */ T *impl(T &t) {
return reinterpret_cast<T *>(&const_cast<char &>(reinterpret_cast<const volatile char &>(t)));
}
};
template <typename T>
constexpr T *addressof(T &t)
{
return addressof_impl<has_overloaded_addressof_operator<T>::value>::template impl<T>(t);
}
but this is actually an ODR violation if the same instantiation addressof<X> is used in multiple translation units, some where X is incomplete, and some where X is complete and has an overloaded & operator. This can be re-worked by performing the logic inside addressof directly, using regular overloaded functions.
template <typename T>
std::enable_if_t<has_overloaded_addressof_operator<T>::value, T *>
addressof(T &t)
{
return reinterpret_cast<T *>(&const_cast<char &>(reinterpret_cast<const volatile char &>(t)));
}
template <typename T>
constexpr
std::enable_if_t<!has_overloaded_addressof_operator<T>::value, T *>
addressof(T &t)
{
return &t;
}
(has_overloaded_addressof_operator would need to be inlined too, for the same reason.)
This way, the problem is avoided: when X is incomplete, then addressof<X> refers to a different function than when X is complete.

When is deleting a template instantiation preferable to deleting a non-template overload?

Suppose I have a template that works with raw pointers:
template<typename T>
void processPointer(T* ptr);
I don't want this to be called with void* pointers. It seems I have two choices. I can delete a non-template overload:
void processPointer(void*) = delete;
Or I can delete a template instantiation:
template<>
void processPointer<void>(void*) = delete;
Declaring the non-template overload is easier (no futzing with angle brackets). Are there reasons why I'd prefer to delete the template instantiation instead?
Here's one reason to favor the template version: processPointer<void>(void*) can still be invoked directly, avoiding the other overload.
I don't see any reason to go templating here
In fact, by deleting the non-template overload you may wiggle your way out of some edge-case ambiguous calls that I can't think of right now, since non-templates take precedence over template instantiations. And thus make this work as desired in a majority of cases.
This might give insight:
#include <iostream>
struct X
{
template<typename T>
void processPointer(T* ptr) {
std::cout << "Template\n";
}
// error: explicit specialization in non-namespace scope ‘struct X’
// template<>
// void processPointer(void*) = delete;
// Overload but no specialization
// This will prevent lookup the specialization outside the class, when no
// template argument is explicitly given. However, with an explicit
// template argument the specialization is called.
void processPointer(void*) = delete;
};
// Specialization outside the class body
template<>
void X::processPointer(void* ptr) {
std::cout << "Specialization\n";
}
int main ()
{
X x;
//error: use of deleted function ‘void X::processPointer(void*)’
//x.processPointer((void*)0);
// Explicit template argument:
x.processPointer<void>((void*)0);
}
Conclusion: The answer of #Casey holds.
Suppose you want to pass the argument pointer of type void* (or simply nullptr) to your processPointer function and you also want to call its specialization for type Type. Then you should write
processPointer(static_cast<Type>(pointer));
for
void processPointer(void*) = delete;
But for
template<>
void processPointer<void>(void*) = delete;
you could write the code which is much shorter:
processPointer<Type>(pointer);
So both variants can be used in the different cases.
However the analogue of the variant with non-template overload can be the only way in some cases.
Suppose there is a function template with two parameters:
template<typename T, typename U>
void processPointer(T* ptr1, U* ptr2);
You don't want it to be called with void* pointers as the first argument. The partial specialization of function templates is not allowed in C++ so this code is incorrect:
template<typename U>
void processPointer<void, U>(void*, U*) = delete;
And you must use another one:
template<typename U>
void processPointer(void*, U*) = delete;

When to use template<> in c++

I'm a little bit confused about c++ template specialization.
What is the exact difference between:
template<typename T>
T foo (T a) {
return a;
}
template<>
char* foo<char*> (char* a) {
return a;
}
and
template<typename T>
T foo (T a) {
return a;
}
char* foo<char*> (char* a) {
return a;
}
Also - Does template<> define a second template?/ If so what could be the use of that?
Regards and thank's for any help
The second one is simply invalid syntax. You cannot use a template parameter in a function declaration unless you have declared the function to be a template.
The first one declares a specialization of the function template foo. Whenever you use foo with template parameter char * the specialization is used instead of the original definition.
The template <> notation introduced a full specialization of a template: that is, the general version of the template is not used when the deduced template parameters are those of the full specialization. However, any deviation would still use the general template:
foo(17); // uses your general template
foo("hello"); // also uses your general template! T is deduced as char const*
char world[] = "world";
foo(world) // uses your specialization
In principle, this is exactly who overloading would work! Obviously, for class templates there is no overloading and you'd need to specialize them. However, even for function templates specialization is reasonable: when the template arguments are explicitly specified:
foo<char*>(world); // calls the specialization
If you use overloading instead, the overload wouldn't be used:
template <typename T>
void bar(T) { /*...*/ }
void bar(char*) { /*...*/ }
bar(world); // calls the bar(char*) overload
bar<char*>(world); // calls the template
With respect to your two alternatives: the second alternative isn't legal C++. The second definition looks a bit like a specialization but you need to introduce a specialization using template <>.