且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

为什么将运算符void *()转换函数添加到C ++流类中?

更新时间:2022-01-30 08:40:44

std :: stringstream $ c $的功能是什么? c>的目的是,如果流用作 bool ,则如果将流转换为 true 流仍然有效,如果不是,则为 false 。例如,如果您实现自己的词法转换版本,则可以使用一种简单的语法。

A feature of std::stringstream is that it is intended that if the stream is used as a bool, it gets converted to true if the stream is still valid and false if it's not. For instance this lets you use a simple syntax if you implement your own version of lexical cast.

(供参考, boost 包含一个名为 lexical_cast 的模板函数,其功能类似于以下简单的模板函数。)

(For reference, boost contains a template function called lexical_cast which does something similar to the following simple template function.)

template <typename T, typename U>
T lexical_cast(const U & u) {
    T t;
    std::stringstream ss;
    if (ss << u && ss >> t) {
        return t;
    } else {
        throw bad_lexical_cast();
    }
 }

例如,如果您从事的项目有例外

If for instance, you work on a project where exceptions are disallowed, you might want to roll the following version of this instead.

template <typename T, typename U>
boost::optional<T> lexical_cast(const U & u) {
    T t;
    std::stringstream ss;
    if (ss << u && ss >> t) {
        return t;
    } else {
        return boost::none;
    }
 }

(上述方法有多种改进方法,

(There are various ways the above could be improved, this code is just to give an example.)

运算符void * 的用法如下: :


  1. ss<< u 返回对 ss 的引用。

  2. ss 隐式转换为 void * ,如果流操作失败,则为 nullptr ;如果

  3. && 运算符会迅速终止,具体取决于该指针的真值。
  4. >
  5. 第二部分 ss>> t 运行并返回,并转换为 void *

  6. 如果两项操作均成功,则我们可以返回流式结果 t 。如果其中任何一个失败,则表明存在错误。

  1. ss << u returns a reference to ss.
  2. The ss is implicitly converted to void * which is nullptr if the stream operation failed, and non-null if the stream is still good.
  3. The && operator aborts quickly, depending on the truth value of that pointer.
  4. The second part ss >> t runs, and returns and is also converted to void *.
  5. If both operations succeeded then we can return the streamed result t. If either failed then we signal an error.

布尔值转换功能基本上就是语法糖,它可以实现此目的(以及许多其他功能)

The bool conversion feature is basically just syntactic sugar that allows this (and many other things) to be written concisely.

实际上引入隐式布尔转换的缺点是 std :: stringstream 可以隐式转换为 int 以及其他许多类型,因为 bool 可以隐式转换为 int

The drawback of actually introducing an implicit bool conversion is that then, std::stringstream becomes implicitly convertible to int and many other types also, because bool is implicitly convertible to int. This ultimately causes syntactic nightmares elsewhere.

例如,如果 std :: stringstream 具有隐式的 operator bool 转换,假设您有以下简单代码:

For instance, if std::stringstream had an implicit operator bool conversion, suppose you have this simple code:

std::stringstream ss;
int x = 5;
ss << x;

现在,在重载分辨率中,您有两个潜在的重载需要考虑(!),通常是一个 operator<<(std :: stringstream& int),然后将 ss 转换为 bool ,然后提升为 int ,并且移位运算符可以应用 operator<<(int ,int),这都是因为隐式转换为 bool ...

Now in overload resolution, you have two potential overloads to consider (!), the normal one operator<<(std::stringstream &, int), and the one in which ss is converted to bool, then promoted to int, and the bit shift operator may apply operator<<(int, int), all because of the implicit conversion to bool...

解决方法是改为使用隐式转换为 void * ,该转换可以在上下文中用作布尔值,但实际上不能隐式转换为bool或int。

The workaround is to use an implicit conversion to void * instead, which can be used contextually as a bool, but isn't actually implicitly convertible to bool or int.

在C ++ 11中,我们不再需要这种解决方法,并且没有理由没有人会明确使用 void * 转换,因此将其删除。

In C++11 we don't need this workaround any more, and there's no reason that anyone would have explicitly used the void * conversion, so it was just removed.

(我在寻找参考,但我相信该函数的值仅在应该是 nullptr 不是 nullptr ,而是实现定义了它可能产生的非零指针值。因此,任何依赖 void * 版本的代码都无法正确重构以使用 bool 版本,这是不正确的

(I'm searching for a reference, but I believe that the value of this function was only specified up to when it should be nullptr vs. when it should not be nullptr, and that it was implementation defined what nonzero pointer values it might yield. So any code that relied on the void * version and cannot be trivially refactored to use the bool version would have been incorrect anyways.)

void * 解决方法仍然并非没有问题。为了增强功能,为C ++ 11之前的代码开发了更复杂的安全布尔惯用语,该iiuc基于类似 T * 的东西,其中 T 是一次使用类型,例如在实现该习语的类中定义的结构,或者对该类使用指针成员函数并使用返回值该类的特定私有成员函数或nullptr。例如,所有boost智能指针都使用安全布尔习惯用法。

The void * workaround is still not without problems. In boost a more sophisticated "safe bool" idiom was developed for pre-C++11 code, which iiuc is based on something like T* where T is either a "type-used once", like a struct which is defined in the class implementing the idiom, or using a pointer-to-member function for that class and using return values which are either a particular private member function of that class, or nullptr. The "safe bool" idiom is used for instance in all of the boost smart pointers.

尽管在C ++ 11中通过引入显式运算符bool 。

Regardless this whole mess was cleaned up in C++11 by introducing explicit operator bool.

此处提供更多信息:

More info here: Is the safe-bool idiom obsolete in C++11?