Reputation: 98
template<class T>
inline T Library<T>::get_isbn()
{
T temp;
cout << "Enter the name/no:" << endl;
cin >> temp;
string ka;
if (typeid(temp) == typeid(ka))
{
while (islower(temp[0]))
{
cout << " Pls enter the using the first letter as capital" << endl;
cin >> temp;
}
}
}
return temp;
}
I'm creating a template class which can take either integer or string
as template parameter and when I create an object of the class with T
as string
, it's going in the loop and everything's works fine. But when I create an object with int
as template parameter, it gives me following two errors:
error C1903: unable to recover from previous error(s); stopping compilation
error C2228: left of '.at' must have class/struct/union
I want that if parameter passed is string
, then only the code for checking the first alphabet to be capital should run, else when I give the template parameter as int
, it shouldn't check for the first alphabet thing.
Upvotes: 2
Views: 7548
Reputation: 624
The typeid is not a constexpr, so it cannot impact on the template content during compilation stage. All stuff must be compiled.
C++ 17 has introduced if constexpr statement, so it is possible to define a function in a similar way to your example:
#include <string>
#include <cctype>
#include <iostream>
#include <type_traits>
template<class T>
inline T get_isbn()
{
T temp;
std::cout << "Enter the name/no:" << std::endl;
std::cin >> temp;
std::string ka;
// if (typeid(temp) == typeid(ka)) // It is not a constexpr.
// if constexpr compiles only when condition is met.
// Passing types directly to std::is_same
// if constexpr (std::is_same<T, std::string>::value)
// Deducing types using decltype()
if constexpr (std::is_same<decltype(temp), decltype(ka)>::value)
{
while (std::islower(temp[0]))
{
std::cout << " Pls enter the using the first letter as capital" << std::endl;
std::cin >> temp;
}
}
return temp;
}
int main()
{
const auto isbn_int = get_isbn<int>();
std::cout << "The ISBN<int> is: ["<< isbn_int << "]" << std::endl;
const auto isbn_string = get_isbn<std::string>();
std::cout << "The ISBN<string> is: ["<< isbn_string << "]" << std::endl;
return 0;
}
// Sample input/output:
// Enter the name/no:
// 123
// The ISBN<int> is: [123]
// Enter the name/no:
// My-ISBN-Number
// The ISBN<string> is: [My-ISBN-Number]
Before C++17, you must use template specialization, as @dyp mentioned.
Upvotes: 0
Reputation: 39121
An if
in C++ is always (semantically) a run-time decision. It may be evaluated by the compiler at compile-time, and the unused branch thrown away. But it may doesn't mean it must. You still have to ensure all branches contain valid code.
In this example, the expression temp[0]
is ill-formed if temp
is an integer. The simplest solution would be to call an overloaded function inside your generic function -- note: by introducing a typeid
-branching, your algorithm inherently isn't generic any more, it requires special treatment for some types.
template<class T>
void get_isbn_impl(T&)
{
// default implementation
}
void get_isbn_impl(string& str)
{
// special version for `string`
while (islower(str[0]))
{
cout << " Pls enter the using the first letter as capital" << endl;
cin >> str;
}
}
template<class T>
inline T Library<T>::get_isbn()
{
T temp;
cout << "Enter the name/no:" << endl;
cin >> temp;
get_isbn_impl(temp);
return temp;
}
It is also possible to specialize either Library<string>
(the whole class) or just Library<string>::get_isbn
.
Upvotes: 3