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 <>.
Related
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.
Let's say I have a class template:
template <typename T>
class Array {
...
int length() const;
};
The definition of length would be
template <typename T>
int Array<T>::length() const
{
...
}
But why wouldn't it be? (I)
int Array<T>::length() const
{
...
}
Or maybe: (II)
template <typename T>
int Array::length() const
{
...
}
I guess (II) would be a function template. But actually I cannot understand the logic behind this syntax. Any rules to understand templates syntax?
int Array<T>::length() const
{
...
}
Illegal if:
you have not declared a class called T
you have not used typedef to give an existing type a new name - T
ex:
class T;
typedef double T;
using T = double;
template <typename T>
int Array::length() const
{
...
}
Illegal if:
you don't have a class called Array - different from template <class T> Array
Why it can't be (I) is easy: Without the template line, the compiler would have no choice but to interpret the < as a less-than operator, which would definitely not result in a useful function definition.
For (II) we need to consider how you would represent a function template of a class template. Say your class looked like this:
template <typename T>
class Array {
...
template <typename U>
int length() const;
};
Now you need to be able to explicitly specify which component takes which template parameter. Without explicitly specifying the <T> and <U> you would have at minimum a bunch of confusion about which parameter applies to which template. At worst it would be ambiguous and uncompilable.
template <typename T>
int Array::length() const
There may be partial specializations of a template. How is the compiler supposed to know whether this is a definition for the member of the primary template or a partial specialization?
int Array<T>::length() const
Every name in C++ must be declared. T, if to be used as a template parameter, must also be declared as one. You haven't, therefore the compiler will look for an earlier declaration and issue an error message as he finds none.
I am writing a comparator for strings. However I want it to work for both strings and char*s.
Something like StringComparer<std::string, std::string> and StringComparer<const char *, const char*>. Of course, inside the implementation for Stringcomparer<const char *, const char *> I will simply do a std::string Stringversion(<pass the const char* here>) for both strings and simply call the Stringcomparer<std::string, std::string>.
How can I write two such templated functions for my Stringcomparer.
I have been looking for this and all I can find everywhere are examples where people have defined a function like this:
template <typename T> foo(T&)
{
//some operation on T that does depends on operators or functions that can handle any //type like sort or cout. basically there are showing that this fucntion can be used to sort //both integer and string vectors or it can cout both integers and floats.
}
Can you please tell me how I can provide multiple variants of my stringcomparer. Surely there are times when people need to write a separate routine handling each type. How is this accomplished.
You can declare a primary function template and the [fully] specialize it for different types, e.g.:
template <typename T> void foo(T&); // primary template declaration
template <> void foo<std::string>(std::string& s) { // specialization for std::string
// ...
}
template <> void foo<char*>(char *&s) { // specialization for char*
// ...
}
Note that the specializations have to match the primary template with the specialized type replaced exactly! In general, I find it easier to specialize class template implementing function objects (i.e., have a function call operator) and delegate to these from a general function template.
You can use template specialisations. Here is a short example.
template <typename T>
void foo(const T& arg)
{
// code
}
// Specialises the function template for char*
template <>
void foo(const char*& arg)
{
// different code
}
EDIT: Oops, specialised for string to start with.
I'm trying to do specialization to template operator, the template looks like this:
template <typename Iterator1, typename Iterator2>
ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const
after i did the specialization that looks like this:
template <>
float operator()<float*,float*>(float* a, float const* b, unsigned long size, float worst_dist = -1) const
i get an error during compilation :
Cannot specialize a function 'operator()' within class scope
All those function are in struct template
I'll be glad to get some help.
thanks.
Why do you want to specialize this operator anyway? You won't be able to call it using the syntax which depends on specializations (i.e. explicit providing the [some of] the template arguments) anyway! Just use overloading and you should be fine. Although it is sometimes desirable or even necessary to use the notation where you explicitly specify the template arguments, it tends to be not that important for functions in general to use specialization rather than overloading.
I just read things up in the standard and actually is possible to provide an explicit specialization, however it has to be outside of the class definition. For example:
#include <iostream>
struct foo
{
template <typename T> void operator()(T const&) {
std::cout << "general\n";
}
};
template <>
void foo::operator()<int>(int const&) {
std::cout << "int spec\n";
}
int main()
{
foo f;
f(1.2);
f(1);
f<double>(1); // <-- ERROR: doesn't work!
}
This would have worked the same using overloading. Using explicitly specified template arguments still doesn't work, though.
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.