Reputation: 141
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
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
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