可以采用整数或浮点数或双精度数或任何其他可转换为浮点数的 C++ 函数

Posted

技术标签:

【中文标题】可以采用整数或浮点数或双精度数或任何其他可转换为浮点数的 C++ 函数【英文标题】:C++ function that can take integer or float or double or any other castable to float 【发布时间】:2020-07-25 21:12:35 【问题描述】:

我正在尝试在 C++ 中实现 Vector3 结构。我正在重载“*”运算符以处理与标量值的乘法。所以它会像这样工作:

v1 = Vector3(1.0f, 1.0f, 1.0f);
v2 = 2*v1;
v3 = 2.4f*v1;
v4 = 2.4*v1;

所有 3 个操作都将返回一个 Vector3 实例。但是,我不想为此实现 3 个函数。

    Vector3 operator * (int& const val) 
       float _val = static_cast<float> (val);
       return Vector3(x * _val, y * _val, z * _val);
    

   Vector3 operator * (double& const val) 
           float _val = static_cast<float> (val);
           return Vector3(x * _val, y * _val, z * _val);
   
   
   Vector3 operator * (float& const val) 
               return Vector3(x * val, y * val, z * val);
       
    

有没有更好的方法用一个函数来做到这一点?

【问题讨论】:

为什么要引用参数? 对于大值,const 引用更有效,因为它们不涉及复制大量数据。但是,对于数值,数字本身与实际引用的大小相同(即使不小),这意味着将 const 引用作为参数是没有意义的。 光是这么想,const ref 不会更慢吗?优化编译器将使用寄存器(FP 或 int)传递值,因此存在内存访问,const ref 将需要内存访问,地址在寄存器中传递。我知道现代编译器很聪明,但足够聪明,可以在寄存器中按值传递 const ref? 我仍然是 C++ 的初学者。我想你是对的,通过引用传递参数是错误的。它既低效又难以使用。 @Skizz 编译器可以对static 函数进行这样的优化,但不能对extern 函数进行这样的优化(因为它原则上可以从外部调用,因此必须遵守ABI) .此外,并非所有 ABI 都通过寄存器传递参数:例如32 位 x86 在 GCC 和 MSVC 的默认调用约定中为此使用堆栈。 【参考方案1】:

由于您再次将所有类型转换为 float,因此您不需要这样做。

如果您将函数定义为接受float,然后传递int 或任何可转换类型,它将自动转换为float。以下代码表明

#include <typeinfo>
#include <iostream>

struct Vector3

    Vector3(float x, float y, float z): xx, yy, zz
    float x, y, z;
    Vector3 operator*(float val)const
        return Vector3val * x,val * y,val * z;
    
;

int main()
    Vector3 v11,2,3;
    auto v2 = v1*2;
    std::cout << typeid(v2.x).name();

Live

如果你想以相反的顺序使用乘法

#include <typeinfo>
#include <iostream>

struct Vector3

    Vector3(float x, float y, float z): xx, yy, zz
    float x, y, z;
;
Vector3 operator*(float val, const Vector3& v)
    return Vector3val * v.x,val * v.y,val * v.z;


int main()
    Vector3 v11,2,3;
    auto v2 = 2*v1;
    std::cout << typeid(v2.x).name();

为了简单起见,我使用了公共成员。您可能希望将私有的与 setter 和 getter 一起使用。

【讨论】:

谢谢你,这也很好用!作为一个初学者,这么多的语法变化真的让我很困惑。【参考方案2】:

如果您确实必须在内部使用引用参数和 float 数据类型,并且希望避免编译器对隐式转换发出警告,那么您可以使用模板化运算符函数(还要注意 const 限定符的修改位置):

    template<typename T>
    Vector3 operator * (const T& val)
    
        float mul = static_cast<float>(val); // Change this to any specific conversion/cast you want
        return Vector3(x * mul, y * mul, z * mul);
    

您还需要使用Vector3 对象作为* 运算符的第一个 操作数:

int main()

    Vector3 v1 = Vector3(1.0f, 1.0f, 1.0f);
//  Vector3 v2 = 2 * v1;
//  Vector3 v3 = 2.4f * v1; // These won't work!
//  Vector3 v4 = 2.4 * v1;
    Vector3 v2 = v1 * 2;
    Vector3 v3 = v1 * 2.4f; // But these will
    Vector3 v4 = v1 * 2.4;
    return 0;

编辑:如果您想要一个“交换”运算符(即,您可以在任一位置使用 scalar 操作数),那么您可以声明一个 friend 运算符,它需要两个参数(常量和类引用):

    template<typename T>
    friend Vector3 operator * (const T& val, const Vector3& vec)
    
        float mul = static_cast<float>(val); // Change this to any specific conversion/cast you want
        return Vector3(vec.x * mul, vec.y * mul, vec.z * mul);
    

【讨论】:

谢谢,这正是我想要的。如果我想实现级联操作,这种运算符重载不是可交换的会导致问题:(【参考方案3】:

正如我所见,使用 double 定义/声明变体就足够了,它也适用于浮点数和整数。

这是可编译的示例(只是测试和演示):

class Vector3 
public:
    Vector3(double x, double y, double z): x(x), y(y), z(z)  

    Vector3 operator * (double val) 
        return Vector3(x * val,
                       y * val,
                       z * val);
    

private:
    double x  0 ;
    double y  0 ;
    double z  0 ;
;


int main()

    int a = 1;
    float b = 2.1;
    double c = 3.5;

    Vector3 vec1(1, 2.1f, 3);
    Vector3 vec2(a, b, c);

    auto vec3 = vec1 * a;
    auto vec4 = vec1 * b;
    auto vec5 = vec1 * c;

    return 0;

【讨论】:

以上是关于可以采用整数或浮点数或双精度数或任何其他可转换为浮点数的 C++ 函数的主要内容,如果未能解决你的问题,请参考以下文章

检查字符串是不是可以在 Python 中转换为浮点数

如何在 x86(32 位)程序集中将无符号整数转换为浮点数?

在 Swift 中将半精度浮点数(字节)转换为浮点数

C:将最小 32 位整数 (-2147483648) 转换为浮点数给出正数 (2147483648.0)

在 C 中的某些整数上使用位操作中断将整数转换为浮点数

如何比较浮点数或双精度数? [复制]