2
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.

dyp
  • 38,334
  • 13
  • 112
  • 177
khpatel4991
  • 98
  • 1
  • 9
  • After formatting, you seem to have too many closing braces `}`. – dyp Nov 09 '13 at 10:03
  • 1
    Your code does not contain calls to at() so you did not post actual code. – Öö Tiib Nov 09 '13 at 10:08
  • This is now possible with if_constexpr. See https://stackoverflow.com/questions/69375132/how-can-i-use-different-struct-as-template-argument-in-a-template-function – Dragonsheep Sep 19 '22 at 07:11

2 Answers2

3

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.

dyp
  • 38,334
  • 13
  • 112
  • 177
0

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.

Michał Jaroń
  • 469
  • 4
  • 11
  • [`std::type_info::operator==`](https://en.cppreference.com/w/cpp/compiler_support/23) becomes `constexpr` in C++23. – HolyBlackCat May 23 '23 at 08:06
  • Ok, I didn't find it in documentation, but even if `operator==` is `constexpr`, operator typeid() still isn't `constexpr` - because it recognizes polymorphic types, not known during compilation stage. – Michał Jaroń May 23 '23 at 10:11
  • I believe this only matters if you apply it to a reference to a polymorphic type. Otherwise it should work at compile-time (otherwise what would be the point of the constexpr `==`). – HolyBlackCat May 23 '23 at 10:14