Program fails to call the specialized template implementation - c++

I am trying to learn C++ template. While I run the following example, the program couldn't call the specialized template implementation. Therefore, I got the wrong output. Could anybody tell why?
template <class T>
T max(T a, T b)
{
cout << "2 ..." <<endl;
return a > b ? a : b;
}
template<>
char* max(char* a, char* b)
{
cout << "1 ..." <<endl;
return strcmp(a, b) > 0 ? a : b;
}
int main()
{
cout << max("Aladdin", "Jasmine") << endl;
return 0;
}

The arguments are passed as constant char. Therefore, try the following code instead. Note that I also included the necessary header file includes. Moreover, it is highly advisable to use std::cout, or use using std::cout;.
#include <iostream>
#include <cstring>
template <class T>
T max(T a, T b)
{
std::cout << "2 ..." << std::endl;
return a > b ? a : b;
}
template<>
const char* max(const char* a, const char* b)
{
std::cout << "1 ..." << std::endl;
return std::strcmp(a, b) > 0 ? a : b;
}
int main()
{
std::cout << max("Aladdin", "Jasmine") << std::endl;
return 0;
}

The reason you're seeing the issue is that the arguments you're passing are of type char const * (also can be spelled const char *). There isn't any standard way that I know of in C++ to print out the full name of a type. But there is a way to test this sort of thing..
One of the problems of templates is that the system will expand any templates it can. And so you will have code mysteriously work a certain way and not be completely sure why. One way you could've gotten the compiler to tell you exactly what the problem was in this case was to try to remove the template:
#include <iostream>
#include <cstring>
using ::std::cout;
using ::std::strcmp;
char* max(char* a, char* b)
{
cout << "1 ..." << '\n'; // Don't use ::std::endl Use cerr if you need flushing.
return strcmp(a, b) > 0 ? a : b;
}
int main()
{
cout << max("Aladdin", "Jasmine") << '\n';
return 0;
}
The compiler would've helpfully told you that you were trying to call a function that took non-const arguments with const arguments, and you would've learned exactly what the problem was.

Related

how to return a reference to a default value of a non-type template argument

I have done a lot of research on this but I wasn't able to find a design pattern addressing the problem. This is a minimal description of what I'm trying to perform.
#include <iostream>
using namespace std;
template <class T, T default_value=T{}>
class A{
private:
T inclassValue;
public:
A(T icv):inclassValue{icv}{}
const T& operator[](int k){
if(k==1) return inclassValue;
return default_value;
}
};
struct two_int{int x;int y;};
int main(){
A<int> a{4};
cout << "a[0]=" << a[0] << endl;
cout << "a[1]=" << a[1] << endl;
/*
A<two_int> b{{3,5}};
cout << "b[0]=" << b[0].x << "," << b[0].y << endl;
cout << "b[1]=" << b[1].x << "," << b[1].y << endl;
*/
return 0;
}
The code will compile, link and output as expected
a[0]=0
a[1]=4
The compiler complains though and issues a warning for the line of code where default_value is used
return default_value;//Returning reference to local temporary object
which makes some sense. Uncommenting the last part in main and compiling, the compiler issue this time an error while building the template
template <class T, const T default_value= T{}>//A non-type template parameter cannot have type 'two_int'
while what I ideally hope for is
b[0]=0,0
b[1]=3,5
I was able to come up with a solution by adding an extra helper class, that will provide the default_value of T (as a static member), to the template arguments. I'm not convinced by the robustness of my trick and I was wondering if there exists a design pattern addressing this. The warning for types and the error for non-types. Also, I shall add that my primary goal is to be able to provide default_value at will (6 for int for example instead of 0).
Thanks
Not exactly sure what you're looking for, but perhaps a static helper finishing for creating a static default T could be useful:
template <typename T>
static const T& default_value() {
static const T* t = new T{};
return *t;
}
Note this will construct T at most once even across threads (in c++11), but still never destruct T. Since it's static, it's likely the lack of destruction is acceptable, but this of course depends on T.
Here is one version that forwards arguments to the constructor of a default_value stored as constexpr. You are quite limited here as to what is valid to pass as arguments (not sure exactly how limited) so it will depend on your use-case.
#include <iostream>
using namespace std;
template <class T, auto... Args>
class A{
private:
T inclassValue;
constexpr static T default_val = T{Args...}; // Changed to curly brackets here
public:
constexpr A(T icv):inclassValue{icv}{}
const T& operator[](int k){
if(k==1) return inclassValue;
return default_val;
}
};
struct two_int{int x;int y;};
int main(){
A<int> a{4};
cout << "a[0]=" << a[0] << endl;
cout << "a[1]=" << a[1] << endl;
A<two_int> b{{3,5}};
cout << "b[0]=" << b[0].x << "," << b[0].y << endl;
cout << "b[1]=" << b[1].x << "," << b[1].y << endl;
return 0;
}

String comparison using general comparators

I am trying to see what happens when we compare strings directly using operators like <, >, etc. The two usages in the code below surprisingly give different answers. Aren't they exactly same way of saying things?
#include <iostream>
template <class T>
T max(T a, T b)
{
//Usage 1:
if (a > b) return a; else return b;
//Usage 2:
return a > b ? a : b ;
}
int main()
{
std::cout << "max(\"Alladin\", \"Jasmine\") = " << max("Alladin", "Jasmine") << std::endl ;
}
Usage 1 gives "Jasmine" while usage 2 gives "Alladin".
When you use:
max("Alladin", "Jasmine")
it is equivalent to using:
max<char const*>("Alladin", "Jasmine")
In the function, you end up comparing pointers. The outcome of the call will depend on the values of the pointers. It is not guaranteed to be predictable.
Perhaps you want to use:
max(std::string("Alladin"), std::string("Jasmine"))
or
max<std::string>("Alladin", "Jasmine")
Be warned that some compiler might pick up std::max when you use that. You may want to change max to my_max or something like that.
You are not actually comparing the string in your code. "Alladin" and "Jasmine" are actually of the type const char[] and they decay into pointers when you call max("Alladin", "Jasmine"). This means that in your function you are comparing the address of the strings and not the contents.
If you meant to test std::strings then you need to create std::strings and pass them to your max function.
Both methods are wrong. Character strings don't have valid > operator.
You can compare std::string instead:
#include <iostream>
#include <string>
template <class T>
T my_max(T a, T b)
{
return a > b ? a : b;
}
int main()
{
std::string a = "Alladin";
std::string b = "Jasmine";
std::cout << "my max: " << my_max(a, b) << std::endl;
//standard max function:
std::cout << "standard max: " << max(a, b) << std::endl;
}
The expected result should always be "Jasmine"

I want to know the type of a variable

I was looking on the C++11 libraries, I'm not goot working with C++ objects and templates but I was trying to read the type of a variable and to run different code, but here there is an example that explains better:
if(is_scalar<typeid(list)>)
cout << list << endl;
else
for(...)
cout << list[i] << endl;
I'm trying to do something similar, I think that function is_scalar is exactly what I need cause I need to split the vectors, arrays, and lists from ints, doubles, or floats, etc.
It's hard to think of having the same variable that has different type in the same program but I'm trying to change it on runtime (still not working) or with pre-processor defines (that causes me the problem now).
I solved my problem, I founded this code that I had to modify a bit
#include <iostream>
#include <vector>
using namespace std;
template< bool B > struct Algorithm {
template<class T1> static int do_it (T1 & a) {
for (int _n(((int)((a).size()))-1), i(0); i <= _n; i++)
cout << *(next(a.begin(),i)) << endl;
cout << endl;
}
};
template<> struct Algorithm<true> {
template<class T1> static int do_it (T1 a) { cout << a << endl; }
};
template<class T1>
int elaborate (T1 A)
{
return Algorithm<std::is_scalar<T1>::value>::do_it( A ) ;
}
int main(){
int a = 42;
vector<int> b;
b.push_back(1);
b.push_back(2);
elaborate(a);
elaborate(b);
return 0;
}
At the end, decltype didn't worked because the compiler tried to "read" code that never was "used".
Did you try to use decltype? This could help you.
http://en.cppreference.com/w/cpp/language/decltype

overloading template function

Currently, I encounter some difficulty in overloading a certain function. here's my code:
template<typename Value>
bool process(Value thisValue)
{
return processAccordingToTheType(thisValue);
}
So, there are two overloaded function of processAccordingToTheType:
bool processAccordingToTheType(int thisValue){}
bool processAccordingToTheType(string thisValue){}
when I try to compile it, it said:
error C2665: 'processAccordingToTheType' : none of the 2 overloads could convert all the argument types
what do I need to do?
Update:
int main()
{
int i = 1;
process <int> (i);
}
From your sample code I understand you need two things to be done:
Call a type specific process function
Restrict these calls to string and int types
Wrapping the processAccordingToType function inside process<T> is completely redundant: process<T> actually means 'process according to type'. The keyword here is 'template specialization'. You need to specialize your 'process according to type' method for int and string.
You can do this as below:
#include <iostream>
using namespace std;
template<typename T>
bool process(T t)
{
// call a Compile-Time Assertion
cout << "I don't want this to be called." << endl;
}
template <>
bool process<int>(int i)
{
cout << "process(int) called." << endl;
}
template <>
bool process<string>(string s)
{
cout << "process(string) called." << endl;
}
int main()
{
process(1);
process(string("s"));
process(1.0d);
}
Output:
process(int) called.
process(string) called.
I don't want this to be called.
Ideally, you want to prevent the users of your API calling process with other types. Allowing them to call and handling this at runtime (like it's done in my example) is not acceptable. You achieve this with Compile-Time Assertions. Read "Modern C++ Designs" by Andrei Alexandrescu for ways of doing that.
Look into template specialization. Does what you're looking for without deferring to another function based on type.
http://www.cprogramming.com/tutorial/template_specialization.html
You can overload function templates with either a non-template function or another template function. Make sure that whatever you do, you test incrementally as template errors are notoriously hard to understand.
http://www.cplusplus.com/doc/tutorial/templates/
#include <iostream>
using namespace std;
template <typename Value>
bool processAccordingToTheType( Value thisValue ){
cout << "Generic Type" << endl;
return false;
}
bool processAccordingToTheType(int thisValue){
cout << "int type" << endl;
return true;
}
template <typename Value>
bool process( Value thisValue ){
return processAccordingToTheType(thisValue);
}
int main( int argc, char* argv[] ){
cout << process( 1 ) << endl;
cout << process( "Hello" ) << endl;
return 0;
}

default argument mismatch in C++?

Consider the following code:
#include <iostream>
class Bar
{
public:
void foo(bool b = false, std::string name = "");
};
void Bar::foo(bool b, std::string name)
{
if (!b)
{
std::cout << "b is false" << std::endl;
}
else
{
std::cout << "b is true" << std::endl;
}
}
int main()
{
Bar myBar;
myBar.foo("bla");
return 0;
}
I guess C++ is not broken, but can anyone please explain why the output is true? I am working on VS 2010 but I also checked in ideone which runs gcc
The compiler is implicitly casting the first parameter, a char const[4], to bool, and results in true.
It's equivalent to
myBar.foo((bool)"bla");
which is also equivalent to
myBar.foo((bool)"bla", "");
Because the "bla" is a char const[4], which decays to const char*, and is cast to a bool. Since it's value is not 0, the cast takes the value true. A simpler example:
#include <iostream>
int main()
{
std::cout << std::boolalpha; // print bools nicely
bool b = "Hello";
std::cout << b << "\n";
}
produces
true
Bool parameter convert "bla" to true.
You need to change order of your parameters.