I expected the 2 definitions below to co-exist because i am adding a type checking code but it gives error as already declared. Why so and what needs to be changed?
#include <iostream>
#include <type_traits>
template<class T, class = std::enable_if_t<std::is_integral_v<T>>>
bool is_even(T value)
{
return ((value % 2) == 0);
}
template<class T, class = std::enable_if_t<std::is_floating_point_v<T>>>
bool is_even(T value)
{
std::cout << "\n Floating point version ";
return false;
}
int main()
{
std::cout << "is_even (4) = " << std::boolalpha << is_even(4);
std::cout << "is_even (4.4) = " << std::boolalpha << is_even(4.4);
}
Errors as below
Error(s):
462942513/source.cpp:13:6: error: redefinition of ‘template<class T, class> bool is_even(T)’
bool is_even(T value)
^~~~~~~
462942513/source.cpp:7:6: note: ‘template<class T, class> bool is_even(T)’ previously declared here
bool is_even(T value)
^~~~~~~
462942513/source.cpp: In function ‘int main()’:
462942513/source.cpp:22:69: error: no matching function for call to ‘is_even(double)’
std::cout << "is_even (4.4) = " << std::boolalpha << is_even(4.4);
^
462942513/source.cpp:7:6: note: candidate: template<class T, class> bool is_even(T)
bool is_even(T value)
^~~~~~~
462942513/source.cpp:7:6: note: template argument deduction/substitution failed:
Even this syntax without default arguments doesn't work
#include <iostream>
#include <type_traits>
template<class T, std::enable_if_t<std::is_integral_v<T>>>
bool is_even(T value)
{
return ((value % 2) == 0);
}
template<class T, std::enable_if_t<std::is_floating_point_v<T>>>
bool is_even(T value)
{
return false;
}
int main()
{
std::cout << "is_even (4) = " << std::boolalpha << is_even(4) << "\n";
std::cout << "is_even (4.4) = " << std::boolalpha << is_even(4.4) << "\n";
}
Why so and what needs to be changed?
From std::enable_if 's documentation:
A common mistake is to declare two function templates that differ only in their default template arguments. This does not work because the declarations are treated as redeclarations of the same function template (default template arguments are not accounted for in function template equivalence).
One way to solve this problem in your given example would be to use the enable_if_t
expression when specifying the return type of the function template instead of as a default argument, as shown below:
template<class T>
std::enable_if_t<std::is_integral_v<T>,bool> is_even(T value)
{
return ((value % 2) == 0);
}
template<class T>
std::enable_if_t<std::is_floating_point_v<T>, bool> is_even(T value)
{
std::cout << "\n Floating point version ";
return false;
}
#include <iostream>
#include <type_traits>
template<class T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
auto is_even(T value)
{
return ((value % 2) == 0);
}
template<class T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
auto is_even(T value)
{
std::cout << "\n Floating point version ";
return false;
}
int main()
{
std::cout << "is_even (4) = " << std::boolalpha << is_even(4);
std::cout << "is_even (4.4) = " << std::boolalpha << is_even(4.4);
}