首页 > 解决方案 > 显式转换运算符与同一类中的第二个隐式转换运算符的危险

问题描述

我发现自己处于一种情况,我很想将两个转换运算符放在一个类中。通常我会像避免瘟疫一样避免这种情况。但是使用 C++ 11 和显式转换运算符,我想要实现的似乎既合理又安全。但是我需要一个健全性检查。

考虑以下类(“距离”),旨在将距离值与其测量单位联系在一起。

enum class Unit { None = 0, Meter = 1, Foot = 2, }; // None means INVALID

class Distance
{
    Unit   m_unit;
    double m_value;

public:
    Distance() : m_unit(Unit::None), m_value(0.f) {}  // construct invalid
    Distance(Unit u, double, v) : m_unit(u), m_value(v) {}

    Unit   unit() const  { return m_unit; }

    // Two functions that I would like to make into cast operators:

    double value() const { return m_value; }
    bool valid() const { return Unit::None != m_unit; }

    // Cast operators I would LIKE to add and use.  Implicitly cast to
    // double but in "if()" scenarios, cast to bool to check validity

              operator double() const { return m_value; }
     explicit operator bool()         { return valid(); }
};

由于 Distance 对象应该被视为一个双精度值(大多数情况下),因此我考虑添加隐式双精度转换(上图)。但是在某些情况下,距离可以被认为是“无效的”,由 Unit::None 的单位值表示。在那种情况下,我真的很喜欢添加显式布尔转换的想法。

最终目标是能够替换当前如下所示的代码:

void doSomething(bool b)   {}
void doSomething(double d) {}

void DumpDistance(const Distance& dist)
{
    if (dist.valid())
        std::cout << dist.value() << std::endl;

    doSomething(dist.valid());  // properly calls bool version  
    doSomething(dist.value());  // properly called double version
}

进入这个:

void DumpDistance(const Distance& dist)
{
    if (dist)                           // treated as bool (good)
        std::cout << dist << std::endl; // treated as double (good)

    doSomething(dist);                  // calls double overload (good)
}

在我的测试中,显式布尔运算符似乎可以解决问题。但我不确定。看起来正在调用所需的重载。但在 1990 年代黑暗的过去,我对选角操作员有一种内在的厌恶。

所以我的问题:

这真的像看起来那样安全吗? 是否有一些我遗漏的明显情况,编译器会抱怨转换不明确,或者更糟糕的是,当我想要另一个运算符时,会默默地调用一个运算符?

(要清楚:我不是在问这个的必要性,也不是关于它的可读性。只是关于编译时歧义或我不想发生的转换的危险。我需要巩固显式转换运算符的概念我的头。 )

标签: c++c++11

解决方案


推荐阅读