Hi everyone.

Today i have been playing with templates and decided to make a generic question and answer function using templates to allow you to choose the return type for each call.
Code below.

template< class T >
T qAndA(const std::string Question,const T retType)
{
	T retVar;
	std::cout<<Question<<std::endl; //ask the question
	std::cin>>retVar; //get the response
	return retVar;
}

using namespace std;
int main(int argc, char* argv[])
{
	string meh;
	meh = qAndA("What! is your quest?: ",meh);
	cout<<"you entered "<<meh<<endl;
	cin.ignore(1000,'\n');

	int x = 0;
	x = qAndA("What is your favourite Number",x);
        cout<<"you entered "<<x<<endl;
	cin.ignore(1000,'\n');

	char ch = 0;
	ch = qAndA("What is your favourite Letter",ch);
	cout<<"you entered "<<ch<<endl;
	cin.ignore(1000,'\n');

	return 0;
}

The thing i would like to do is that if T is a string i would like to use getline instead of cin so i can read a string with spaces in it. Also any comments of how im using templates so far would be appreciated.

I would like to make it known at this point the reason i have T in the input side is that from my understanding the template return type in this function is defined soley by the input type.

I was hoping i could do something like if( T==std::string ){ getline(cin,retVar); } but it doesn't like that idea.

Any hope appreciated thanks :)

Template specialization like so :

//for general types
template<typename T>
T ask(const std::string& question){
	cout << typeid(T).name() << endl;
	cout << question << endl;
	T answer;
	cin >> answer;
	return answer;
}
//specialize for string type
template<>
std::string ask(const std::string& question){
	cout << "In string\n";
	cout << question << endl;
	cin.ignore(256,'\n');
	std::string answer;
	getline(cin,answer);
	return answer;
}

Edited 6 Years Ago by firstPerson: n/a

Ahh cool. Just one thing then, in the template version using T How does it know what type to return? i would like for float, double, int and char do i give it the type i want like before for that?

Ahh cool. Just one thing then, in the template version using T How does it know what type to return? i would like for float, double, int and char do i give it the type i want like before for that?

Since we can't overload by return types, yes we have to specify the return type like that.

Ok iv tried what you said and im geting a new error now. It says "error C2912: explicit specialization; 'std::string qAndA(const std::string)' is not a specialization of a function template "

( i tried making the std::string version have a second input, but that then gave me ambigious call error so i knew that couldent be the right way as it cant tell them apart)

The code now looks like this incase i have made some kind of mistake

template< class T >
T qAndA(const std::string Question, T retType)
{
	T answer;
	std::cout<<Question<<std::endl; //ask the question
	std::cin>>answer; //get the response
	std::cout<<"returning a "<<typeid(T).name()<<std::endl;
	return answer;
}
template<>
std::string qAndA(const std::string Question)
{
	std::cout<<Question<<std::endl; //ask the question
	std::string answer;
	getline(std::cin, answer);
	std::cout<<"returning a string"<<std::endl;
	return answer;
}

using namespace std;
int main(int argc, char* argv[])
{
	string meh;
	meh = qAndA("What! is your quest?: ");
	cout<<"you entered "<<meh<<endl;
	cin.ignore(1000,'\n');

	int x = 0;
	x = qAndA("What is your favourite Number",x);
    cout<<"you entered "<<x<<endl;
	cin.ignore(1000,'\n');

	char ch = 0;
	ch = qAndA("What is your favourite Letter",ch);
	cout<<"you entered "<<ch<<endl;
	cin.ignore(1000,'\n');

	return 0;
}

If you think its better instead of giving me the answer can you link me an article that i can read and try to work this out?

Thanks

Edited 6 Years Ago by Kanoisa: n/a

So it knows what type i want to return. It wont just figure it out itself will it?

I got the solution from those links. Thanks it was how i specified the specilisation. The correct way i was looking for was

std::string qAndA<std::string>(const std::string Question, std::string retType )
{
	std::cout<<Question<<std::endl; //ask the question
	std::string answer;
	getline(std::cin, answer);
	std::cout<<"returning a string"<<std::endl;
	return answer;
}

It works now thanks for the help and the useful links :)

Much appreciated .... just got the fix the problem if i enter a type it does not expect now :P

So it knows what type i want to return. It wont just figure it out itself will it?

Its considered bad practice to do that. You should not have an extra parameter like that for no reason. And whats with the snotty attitude?

Also another way to solve your problem is like this :

template<typename T> 
T getUserInput(){
	T val = T();
	cin >> val;
	return val;
}
template<>
string getUserInput(){
	string val;	
	getline(cin,val);
	return val;
}

template<typename T>
T ask(const string& question){
	cout << question << endl;
	return getUserInput<T>();	
}

Aplogies i didnt intend to sound like i had an attitude it was a genuine curious question.

However without the T in the input side i got errors from VS saying "could not deduce template argument for 'T'" That is why i chose to give it a type as a second input at the start.

You guys have looked over the main point here. You cannot do a template specialization of a function for only a templated return type. That's why Kanoisa had to put a dummy parameter to the function, otherwise the compiler will not allow the specialization and say, in this case, "explicit specialization ... is not a specialization of a function template".

As you did Kanoisa is OK. If you want to avoid the overhead of passing a variable of type T to the function, you can use the type2type idiom for the dummy parameter, as so (taken from Modern C++ Design by Alexandrescu):

template <class T>
struct Type2Type { //create a dummy template class that occupies no memory.
  typedef T OriginalType;
};

template< class T >
T qAndA(const std::string Question, Type2Type<T>)
{
	T answer;
	std::cout<<Question<<std::endl; //ask the question
	std::cin>>answer; //get the response
	std::cout<<"returning a "<<typeid(T).name()<<std::endl;
	return answer;
}
template<>
std::string qAndA(const std::string Question, Type2Type<std::string>)
{
	std::cout<<Question<<std::endl; //ask the question
	std::string answer;
	getline(std::cin, answer);
	std::cout<<"returning a string"<<std::endl;
	return answer;
}

using namespace std;
int main(int argc, char* argv[])
{
	string meh;
	meh = qAndA("What! is your quest?: ",Type2Type<string>());
	cout<<"you entered "<<meh<<endl;
	cin.ignore(1000,'\n');

	int x = 0;
	x = qAndA("What is your favourite Number",Type2Type<int>());
    cout<<"you entered "<<x<<endl;
	cin.ignore(1000,'\n');

	char ch = 0;
	ch = qAndA("What is your favourite Letter",Type2Type<char>());
	cout<<"you entered "<<ch<<endl;
	cin.ignore(1000,'\n');

	return 0;
}

Thanks Mike.

That works perfect and as you say its more efficient.

Problem closed :)

>>You guys have looked over the main point here. You cannot do a template specialization of a function for only a templated return type

I don't think you or OP got what I was saying.

First there is a syntax to tell the compiler which template type to instantiate like so:

//psuedo
var ret = templateFunction<Type1,Type2...TypeN>(arg0...arg1);

So to return to the main point, it is wiser and faster to do this :

string name = qAndA<string>(someQuestion);
double age = qAndA<double>(otherQuestion);

than to do what both of you guys were suggesting. I am not sure whats the confusion here?

@firstPerson: Your right! I was confused with partial template specialization. The problem was never about calling the function and getting to compiler to instantiate the function template, but about the specialization of the template based solely on the return type. From one of Kanoisa's posts, it seems his compiler did not allow for specialization of the function template if only the return type was templated. But the C++ standard (and thus a standard compiler like gcc), will allow total specialization of a function template based on a templated return type, but it will not allow a partial specialization of a function template like:

//generic function template prototype:
template<class T, class U>
T foo(U);
//Illegal partial specialization:
template<class U>
int foo(U) { .. };

But your right, in this context, it appears it works fine as you showed. I was wrong to generalize the rule of illegal partial specializations by return type to total specialization by return type only.

This question has already been answered. Start a new discussion instead.