Jytug Jytug - 24 days ago 8
C++ Question

Accessing a class member in an if statement using std::is_same

I'm trying to tackle the following problem: I would like to do an

if
statement that does something depending on whether the argument of a template is a specific object or not - and if it is, call the object's member function. Let's say I want an
std::string


the snippet:

#include <iostream>
#include <string>

template <typename T>
void is_string(const T& arg) {
if (std::is_same<T, const std::string&>::value)
std::cout << arg.length() << std::endl;
else
std::cout << "The argument is not a string" << std::endl;
}

int main() {
is_string(0);
return 0;
}


It doesn't compile, with the following error:

types.cpp: In instantiation of ‘void is_string(const T&) [with T = int]’:
types.cpp:13:13: required from here
types.cpp:7:13: error: request for member ‘length’ in ‘arg’, which is of non-class type ‘const int’
std::cout << arg.length() << std::endl;


I reckon that what I'm trying to achieve might not be possible in C++11, but I would appreciate some suggestions on how to be able to do such a thing

Answer

In a regular if statement, both branches must be valid code. In your case int.length() makes no sense.

In C++1z you could simply use constexpr if:

if constexpr(std::is_same<T, const std::string&>::value)
    std::cout << arg.length() << std::endl;
else
    std::cout << "The argument is not a string" << std::endl;

demo

In C++11 (or older) you can employ overloading to achieve similar result:

void foo(std::string const& str){
    std::cout << str.length() << std::endl;
}

template<typename T>
void foo(T const&){
    std::cout << "The argument is not a string" << std::endl;
}

template <typename T>
void is_string(const T& arg) {
    foo(arg);
}

demo