Reputation: 281
Here is example code (pg. 700 from C++ Programming: An Object-Oriented Approach by Forouzan & Gilberg.
As I understand, it is to explain function template specialization
, and I have read and seen lots of people saying to avoid this in favor of overloading
, traits class
(whatever that is), and I suppose other methods - so I don't intend on spending too much time on it but I would like to learn it. @Roger Pate has provided an answer with this nice link that I am still absorbing (in the link to a similar question below): http://www.gotw.ca/publications/mill17.htm
1 #include <iostream>
2 #include <string>
3 #include <cstring>
4 using namespace std;
5
6 // Template Function
7 template <typename T>
8 T smaller(const T& first, const T& second)
9 {
10 if (first < second)
11 {
12 return first;
13 }
14 return second;
15 }
16
17 // Specialization of template function (previously defined)
18 // a C-style string is of type: const char*
19 // so replace every "T" with that
20 template <>
21 const char* smaller (const (const char*) & first, const (const char*) & second)
22 //const char* smaller<>(const (const char*)& first, const (const char*)& second)
23 //const char* smaller<const char*>(const (const char*)& first, const (const char*)& second)
24 {
25 if (strcmp (first, second ) < 0)
26 {
27 return first;
28 }
29 return second;
30 }
31
32 int main ( )
33 {
34
35 // Calling template with two string objects
36 string str1 = "Hello";
37 string str2 = "Hi";
38 cout << "Smaller (Hello , Hi): " << smaller (str1, str2) << endl;
39
40 //Calling template function with two C-string objects
41 const char* s1 = "Bye";
42 const char* s2 = "Bye Bye";
43 cout << "Smaller (Bye, Bye Bye)" << smaller (s1, s2) << endl;
44 // cout << "Smaller (Bye, Bye Bye)" << smaller<>(s1, s2) << endl;
45 // cout << "Smaller (Bye, Bye Bye)" << smaller<const char*>(s1, s2) << endl;
46
47 return 0;
48 }
49
50
51 /*
52 The operator < is not defined for a C-style string, meaning we cannot use the template
53 function to find the smaller of the two C-style strings.
54 This operator is defined in the library "string", and so overloads the operator
55 */
The same code, without line numbers and my failed attempts:
/***************************************************************
* Template function definition with specialization *
***************************************************************/
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
// Template Function
template <typename T>
T smaller (const T& first, const T& second)
{
if (first < second)
{
return first;
}
return second;
}
// Specialization of template function
template <>
const char* smaller (const (const char*) & first, const (const char*) & second)
{
if (strcmp (first, second ) < 0)
{
return first;
}
return second;
}
int main ( )
{
// Calling template with two string objects
string str1 = "Hello";
string str2 = "Hi";
cout << "Smaller (Hello , Hi): " << smaller (str1, str2) << endl;
//Calling template function with two C-string objects
const char* s1 = "Bye";
const char* s2 = "Bye Bye";
cout << "Smaller (Bye, Bye Bye)" << smaller (s1, s2) << endl;
return 0;
}
Long story short, my compiler gcc-8
,
2120|1|root@sbh ~/CODING/CppTemplate # Sun 11 08 2019, 08:53:15
/usr/bin/gcc-8 --version
gcc-8 (Debian 8.3.0-19) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
consistently throws this output, regardless of my attempted fixes (below).
2122|1|root@sbh ~/CODING/CppTemplate # Sun 11 08 2019, 08:56:33
g++-8 -Wall -O -std=c++2a templateSpecialization.cpp -o templateSpecialization.out
templateSpecialization.cpp:21:42: error: ISO C++ forbids declaration of ‘parameter’ with no type [-fpermissive]
const char* smaller (const (const char*) & first, const (const char*) & second)
^
templateSpecialization.cpp:21:44: error: expected ‘,’ or ‘...’ before ‘first’
const char* smaller (const (const char*) & first, const (const char*) & second)
^~~~~
templateSpecialization.cpp:21:13: error: template-id ‘smaller<>’ for ‘const char* smaller(const int (*)(const char*))’ does not match any template declaration
const char* smaller (const (const char*) & first, const (const char*) & second)
^~~~~~~
templateSpecialization.cpp:8:3: note: candidate is: ‘template<class T> T smaller(const T&, const T&)’
T smaller(const T& first, const T& second)
^~~~~~~
I noticed this question, which has an answer with the same spirit of functionality, Function template specialization importance and necessity by https://stackoverflow.com/users/124797/jagannath @jagannath ;
template<typename T>
bool Less(T a, T b)
{
cout << "version 1 ";
return a < b;
}
// Function templates can't be partially specialized they can overload instead.
template<typename T>
bool Less(T* a, T* b)
{
cout << "version 2 ";
return *a < *b;
}
template<>
bool Less<>(const char* lhs, const char* rhs)
{
cout << "version 3 ";
return strcmp(lhs, rhs) < 0;
}
int a = 5, b = 6;
cout << Less<int>(a, b) << endl;
cout << Less<int>(&a, &b) << endl;
cout << Less("abc", "def") << endl;
and it seems I am doing all the same modifications to my function template
, e.g. replace every "T" with "const char*" for instance, lines 22 & 23.
I read a little about compilers 'deducing' what to use so I tried in the calls adding the brackets just after the function name (lines 44 & 45).
I'm sure this is simple and possibly covered somewhere else, but I couldn't find it. Probably an explanation in the context of class templates even, but I just started learning templates and this is as far as I got (i.e. pg. 700 in that book).
Even this question Function Template Specialization Error seemed to have similar problems does not match any template declaration
but again, I feel I have followed the pattern, as in lines 21 (author's) and my 22 and 23.
PS: I don't think it is relevant but my environment may be a little weird...
Upvotes: 1
Views: 659
Reputation: 1300
Try defining the type as:
template <>
const char* smaller (const char* const &first , const char* const &second);
Or:
using cstring_t = const char*;
template <>
const char* smaller (const cstring_t& first, const cstring_t& second);
For the first case, const char* const &
, if you use "east const" notation:
char const * const &
You can read from right to left: "Reference to a constant pointer to a constant char". No need for parenthesis.
The second example shows a cleaner example, if you don't want to confuse with the types. Both function signatures resolve to the same type.
Upvotes: 2