Assuming I have a 4 value vector union, used to hold either a spatial coordinate or colour and I wish to use one of two functions to convert between integer and real format, how would I construct the functions?
My (failed) attempt is:
template<class T,
class S,
typename = std::enable_if_t<std::is_floating_point<T>>,
typename = std::enable_if_t<std::is_integral<S>>>
Math::Vec4<T> Colour(S r, S g, S b, S a)
{
return Vec4<T>(r / static_cast<T>(255),
g / static_cast<T>(255),
b / static_cast<T>(255),
a / static_cast<T>(255));
};
template<class T,
class S,
typename = std::enable_if_t<std::is_integral<T>>,
typename = std::enable_if_t<std::is_floating_point<S>>>
Math::Vec4<T> Colour(S r, S g, S b, S a)
{
return Vec4<T>(static_cast<T>(r * 255),
static_cast<T>(g * 255),
static_cast<T>(b * 255),
static_cast<T>(a * 255));
};
The intention here is to instantiate 1 for cases where T is real and S is integer (convert from integer to real) and 2 for cases where T is integer and S is real. Ideally I'd like to use the same name for both and for the compiler to decide which to use based on the input type. At the moment I get a compiler error, "function template has already been defined".
Also, is this a bad idea?
Update: I've produced a minimal repro based on Tartan's answer, that doesn't compile (can't deduce template argument). Where did I err?
#include <limits>
#include <type_traits>
template<class T>
union Vec3
{
typedef T value_type;
struct
{
T r, g, b;
};
Vec3() = default;
Vec3(T R, T G, T B) : r(R), g(G), b(B) {}
};
template<class T,
class S,
std::enable_if_t<std::is_floating_point<T>::value && std::is_integral<S>::value> * = nullptr>
Vec3<T> Colour(Vec3<S> const & rgb)
{
return Vec3<T>(static_cast<T>(rgb.r) / static_cast<T>(std::numeric_limits<S::value_type>::max()),
static_cast<T>(rgb.g) / static_cast<T>(std::numeric_limits<S::value_type>::max()),
static_cast<T>(rgb.b) / static_cast<T>(std::numeric_limits<S::value_type>::max()));
}
template<class T,
class S,
std::enable_if_t<std::is_integral<T>::value && std::is_floating_point<S>::value> * = nullptr>
Vec3<T> Colour(Vec3<S> const & rgb)
{
return Vec3<T>(static_cast<T>(rgb.r * static_cast<S::value_type>(std::numeric_limits<T>::max())),
static_cast<T>(rgb.g * static_cast<S::value_type>(std::numeric_limits<T>::max())),
static_cast<T>(rgb.b * static_cast<S::value_type>(std::numeric_limits<T>::max())));
}
int main(void)
{
Vec3<float> a(1.0f, 0.5f, 0.25f);
Vec3<char> b;
b = Colour(a);
}