c++ - 基于类型的条件编译

标签 c++ templates

假设我有一个 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_integralstd::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/

相关文章:

c++ - 错误 : ‘father’ is an inaccessible base of ‘son’

c++ - 如何制作一个动态大小的数组?动态数组的一般用法(也可能是指针)?

c++ - 派生到基隐式指针类型转换

c++ - 使用 MSVC 而非 GCC 编译的模板

templates - 在 dotnet 新模板中包含 "hidden"文件

c++ - 我是否在这个通用的 unique_ptr<>() 删除器中正确使用了指针类?

c++ - 声明指针/引用变量的首选方式?

c++ - 遍历 multiset 元素的所有组合

c++ - 如何从成员函数模板类型签名中删除 const?

c++ - 使用流模板以避免复制代码会产生 "error C4430: missing type specifier - int assumed"