假设我有一个 4 值 vector 并集,用于保存空间坐标或颜色,并且我希望使用两个函数之一在整数和实数格式之间进行转换,我将如何构造这些函数?
我的(失败的)尝试是:
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));
};
此处的目的是在 T 为实数且 S 为整数(从整数转换为实数)的情况下实例化 1,在 T 为整数且 S 为实数的情况下实例化 2。理想情况下,我想对两者使用相同的名称,并让编译器根据输入类型决定使用哪个名称。此刻我得到一个编译器错误,“函数模板已经被定义”。
此外,这是个坏主意吗?
更新:我根据 Tartan 的回答生成了一个最小的复现,它不能编译(不能推断模板参数)。我哪里错了?
#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);
}
最佳答案
您的问题是默认模板参数的差异不会声明不同的模板。这就是您收到重新定义错误的原因。
另一个问题是您需要采用 std::is_integral
和 std::is_floating_point
特征的 ::value
,因为 std::enable_if_t
需要一个 bool
,而不是 std::integral_constant
。
要解决这个问题,您可以使用标准的 SFINAE 技巧来声明一个类型的模板参数,该类型取决于 enable_if_t
结果:
template<class T,
class S,
std::enable_if_t<
std::is_floating_point<T>::value && std::is_integral<S>::value
>* = nullptr>
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,
std::enable_if_t<
std::is_integral<T>::value && std::is_floating_point<S>::value
>* = nullptr>
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));
};
关于c++ - 基于类型的条件编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30886184/