AndreasBVB
AndreasBVB

Reputation: 141

C++ Type traits dummy example: compiler error

I ran into some compiler errors recently which boils down into the following dummy example. Basically I am building a "plus2" function template, which I want it to work only on int and float. Logically the program only adds 2 when the "is_numerical" type trait test goes through. However it hangs at compiling with error C2782/C2784/C2676 complaining about adding 2 to a string.

The example is for illustration only and does not make sense. More importantly, what would be the correct way to code this kind of logic up? Thanks.

#include <iostream>
#include <string>
using namespace std;
template <typename T>
struct is_numerical {
    static const bool value = false;
};
template <>
struct is_numerical<float> {
    static const bool value = true;
};
template <>
struct is_numerical<int> {
    static const bool value = true;
};

template <typename T>
T plus2(T input) {
    if (is_numerical<T>::value) {
        return input + 2;
    } else { return input; }
}
int main()
{
    //char x('a'); // prints 'a'
    string x("a"); // compiler error
    cout << plus2(x) << endl;
    return 0;
}

Upvotes: 1

Views: 595

Answers (2)

Drew Dormann
Drew Dormann

Reputation: 63745

The problem is that when T input is a std::string, you're still trying to compile return input + 2;. Even though it's in an if statement that's always false.

In C++17, if constexpr allows conditionally-compiled code.

template <typename T>
T plus2(T input) {
    if constexpr (is_numerical<T>::value) {
        return input + 2;
    } else { return input; }
}

In all standardized versions of C++, SFINAE can also prevent the invalid code from ever being compiled.

template <typename T>
T plus2(T input, typename std::enable_if<! is_numerical<T>::value>::type* = 0) {
    return input;
}

template <typename T>
T plus2(T input, typename std::enable_if<is_numerical<T>::value>::type* = 0) {
    return input + 2;
}

Upvotes: 2

SoronelHaetir
SoronelHaetir

Reputation: 15164

You need to make tests like this part of the function signature rather than the body.,If the function signature matches the compiler is going to try and instantiate it but at that point it fails.

template<typename T>
T plus@2( value, typename std::enable_if<is_numeric<T>::value>::type * = nullptr)
{
  return value + 2;
}

Note that if you then tried passing something for which the test fails you will get a "no matching signature" type error.

Upvotes: 0

Related Questions