如何使用内置返回类型重载运算符?



假设我有一个类,它包装了一些数学运算。让我们使用一个玩具示例

class Test
{
public:
Test( float f ) : mFloat( f ), mIsInt( false ) {}
float mFloat;
int   mInt;
bool  mIsFloat;
};

我想使用以下原型创建一个运算符重载:

float operator=( const Test& test ) 
{ 
if ( !test.mIsFloat ) return *this; // in this case don't actually do the assignment
return test.mFloat;                      // in this case do it.
} 

所以我的问题是:我可以使用内置返回类型重载运算符=吗? 如果是这样,有没有办法引用内置类型?

我知道如果我用类包装内置组件,我可以做到这一点。但在这种情况下,我想让赋值运算符在 LHS 上使用内置类型

用法示例:

Test t( 0.5f );
float f = t; // f == 0.5
int   i = 0;
i = t;       // i stays 0.

更新:非常感谢您的帮助。从玩具的例子中扩展一点,以便人们理解我真正想做的事情。

我有一个配置系统,允许我从不同类型的参数树中获取配置参数(它们可以是整数、浮点数、字符串、数组等)。

我可以通过如下操作从树中获取项目:

float updateTime = config["system.updateTime"];

但"system.updateTime"可能不存在。或者属于错误的类型。通常对于配置,我有一个默认值块,然后代码来覆盖配置中的默认值:

float updateTime = 10;
const char* logFile = "tmp.log";
... etc etc...

我想做这样的事情:

updateTime = config["system.updateTime"];

如果存在替代,则操作成功。因此,如果 operator[] 的返回是树中的"无效"节点,则通常不会发生赋值。

现在我用这样的函数来解决它:

getConfig( config, "system.updateTime", updateTime );

但我更喜欢使用赋值运算符。

如果我愿意创建类来包装内置,我可以这样做。

class MyFloat
{
operator=( const Test& test ) { if (test.isValidNode() ) f = test.float(); return *this; }
float f;
}

但显然,最好不要用琐碎的类包装内置函数,只是为了重载赋值。问题是 - 这在 c++ 中可能吗?

根据您的示例,您真正想要的是一个隐式转换运算符:

class Test
{
// ...
public:
operator float() const;
};
inline Test::operator float() const
{
return mIsFloat ? mFloat : mInt;
}

如果你想有条件地做作业,那么你需要采取另一种方法。 命名方法可能是最好的选择,考虑到所有因素......像这样:

class Test
{
public:
bool try_assign(float & f) const;
};
inline bool Test::try_assign(float & f) const
{
if (mIsFloat) {
f = mFloat;
}
return mIsFloat;
}

无论你做什么,都要注意你引入的语法糖不会导致代码不可读。

你已经有一个从floatTest的隐式转换,以转换构造函数的形式

class Test
{
public:
/* ... */
Test( float f ) : mFloat( f ) /*...*/ {}       
};

这将支持以下转换:

Test t(0.5f);

您可能还需要一个复制分配运算符,以便从floatTest进行进一步的隐式转换:

class Test
{
public:
Test& operator=(float f) { mFloat = f; return *this; }  
};
t = 0.75; // This is possible now

为了支持从Testfloat的隐式转换,你不使用operator=,而是使用自定义的强制转换运算符,声明并实现如下:

class Test
{
public:
/* ... */
operator float () const { return mFloat; }
};

这使得隐式转换成为可能,例如:

float f = t;

顺便说一句,您在这里发生了另一个隐式转换,您甚至可能没有意识到。 在此代码中:

Test t( 0.5 );

文字值0.5不是float,而是double。 为了调用转换构造函数,必须将此值转换为float,这可能会导致精度损失。 要指定float文本,请使用f后缀:

Test t( 0.5f );

使用模板专用化:

class Config {
template<typename T>
void setValue(const std::string& index, T& value); //sets the value if available
};
template<float>
void Config::setValue(const std::string& index, float& value){...} //only sets float values
template<int>
void Config::setValue(const std::string& index, int& value){...} //only sets int values;

不能对基本类型"重载/添加"运算符,但可以为类型Type运算符。但这不会是operator =而是operator >>——就像在istreams中一样。

class Test
{
public:
float mFloat;
int   mInt;
bool  mIsFloat;
Test& operator >> (float& v) { if (mIsFloat) v = mFloat; return *this; }
Test& operator >> (int& v) { if (!mIsFloat) v = mInt; return *this; }
};

然后,您可以:

int main() {
float v = 2;
Test t = { 1.0, 2, false };
t >> v; // no effect
t.mIsFloat = true;
t >> v; // now v is changed
}   

更新

我想做这样的事情:

updateTime = config["system.updateTime"];

然后根据我的建议,你来了:

config["system.updateTime"] >> updateTime;

最新更新