dtell
dtell

Reputation: 2568

Invalid cast error in function template which return values depends on its generic type

I have the following function template

template<typename T>
T foo(){
    if(std::is_same<T,int>::value){
        return 1;
    }
    if(std::is_same<T,std::string>::value){
        return "Hello";
    }
}

I want to apply it like this:

int main(){
    std::cout << foo<int>() << std::endl;    // 1
    std::cout << foo<string>() << std::endl;    // "Hello"
}

If I try to compile my template the compiler throws the following error: error: cannot initialize return object of type 'int' with an lvalue of type 'const char [6]'.

If I remove the second if statement everything compiles fine and I get the correct output therefore I guess the comparison std::is_same<T,int>::value works as intended.

It seems like the Compiler detects the type of T, checks if all return statements match it and throws the error because an std::string is not implicitly castable to int.

Has anyone a solution or another workaround to satisfy my intention?

EDIT

To explain my intention: I am writing a wrapper class for a database cursor class. As these cursors are usually defined it has several member functions like getInt() or getString(). My idea was to implement a generic get<T>() that uses the corresponding cursor member function that depends on T.

Upvotes: 2

Views: 422

Answers (2)

Dustin Nieffenegger
Dustin Nieffenegger

Reputation: 638

Forget the if statements and fully specialize the template function:

template<>
int foo<int>(){
    return 1;
}

template<>
std::string foo<std::string>(){
    return "Hello";
}

Upvotes: 2

Daniel Jour
Daniel Jour

Reputation: 16156

When you reference foo<int>, the compiler generates a function like the following from your template:

int foo<int>(){
    if(true){
        return 1;
    }
    if(false){
        return "Hello";
    }
}

Above code is ill-typed, because (as the compiler tells you) an int cannot be initialized with a C string (char const [N]). Sure, the corresponding return statement will never be reached, but that's something to be figured out by "dead code elimination", which is merely an optimization.

The solution "now" is shown in Dustin's answer, with C++17 we'll get if constexpr which is able to discard code paths the way you expected it:

template<typename T>
T foo(){
    if constexpr (std::is_same<T,int>::value){
        return 1;
    }
    if constexpr (std::is_same<T,std::string>::value){
        return "Hello";
    }
}

Upvotes: 1

Related Questions