【问题标题】:Boost tribool causing right to left conditional evaluation in C++Boost tribool 在 C++ 中导致从右到左的条件评估
【发布时间】:2014-03-26 10:21:45
【问题描述】:

据我所知,C++ 在条件语句中总是从左到右进行计算

if(A, B, C)

A 将首先被评估,B 第二个,依此类推。但是,以下示例表现出一些奇怪的行为。

#include <iostream>
#include <map>
#include <memory>
#include <vector>

#include <boost/logic/tribool.hpp>

//-////////////////////////////////////////////
// File Block
class FileBlock {
public:
    FileBlock();
    virtual ~FileBlock();
    bool linked();

    std::vector<int> messages_;

private:
    boost::logic::tribool position_;
    std::shared_ptr<FileBlock> precedingBlock_ = nullptr;
    std::shared_ptr<FileBlock> followingBlock_ = nullptr;
};

FileBlock::FileBlock()  {
    std::cout << "Breakpoint." << std::endl;

    // "linked()" evaluated first by scope.
    if(linked())    {
        if(!position_
            && precedingBlock_->messages_.back() > 1)   {
                std::cout << "Unreachable." << std::endl;
        }
    }

    // "linked()" evaluated first without the tribool.
    if(linked()
        && precedingBlock_->messages_.back() > 1)   {
            std::cout << "Unreachable." << std::endl;
    }

    // "precedingBlock_->messages_.back() > 1" evaluated first. (Crash because null.)
    if(linked()
        && !position_
        && precedingBlock_->messages_.back() > 1)   {
            std::cout << "Unreachable." << std::endl;
    }
}

FileBlock::~FileBlock() {}

bool FileBlock::linked()    {
    return false;
}

//-////////////////////////////////////////////
// main
int main()  {
    std::shared_ptr<FileBlock> followingBlock(new FileBlock());

    return 0;
}

示例中有三个版本的条件。据我所知,第一个和最后一个应该评估相同。然而,当我在 gdb 中跟踪程序时,当我到达条件的第三个版本时,最右边的条件是第一个被评估的。

限定条件显然可以解决问题(如条件的第一个版本所示),就像第二个条件中所示的完全删除 tribool 一样,但我应该能够使用第三个安然无恙!

由于最左边的条件始终为假,程序应该退出并返回而不做任何事情,但事实并非如此。

这里有什么?我不了解有关 tribool 的内容吗?我是在产生幻觉吗?

这是我正在使用的 mingw 构建以及已安装库的清单:

Core Inventory:
 - autoconf2.5-2.68-1
 - autoconf-10-1
 - automake1.11-1.11.1-1
 - binutils-2.24-1
 - expat-2.1.0-1
 - gcc-c++-4.8.1-4
 - gcc-core-4.8.1-4
 - gdb-7.6.1-1
 - gettext-0.18.3.1-1
 - gmp-5.1.2-1
 - libiconv-1.14-3
 - libltdl-2.4-1
 - libtool-2.4-1
 - make-3.82.90-2
 - mingwrt-4.0.3-1
 - mpc-1.0.1-2
 - mpfr-3.1.2-2
 - pthreads-w32-2.9.1-1
 - w32api-4.0.3-1
 - wsl_rc-4.0-1
 - zlib-1.2.8-1

Auxiliary Inventory:
 - wxWidgets 3.0.0
 - Boost 1.55
 - yaml-cpp 0.5.1

这是我的构建命令:

g++ -std=gnu++11 -O0 -g3 -Wall -c -fmessage-length=0 -o "src\\main.o" "..\\src\\main.cpp" 
g++ -o wtf.exe "src\\main.o" 

【问题讨论】:

    标签: c++ boost c++11 conditional-statements operator-precedence


    【解决方案1】:

    与内置逻辑运算符不同,重载逻辑运算符(和they are overloaded for boost::tribool)没有从左到右的求值顺序(也没有短路语义)。与其他几乎所有地方一样,操作数的求值顺序是未指定的。

    【讨论】:

    • 现在我们有了 lambda,我们应该在 &amp;&amp; 上推动基于短路的重载选项。如果我们想走++ 路线,像template&lt;typename RHS&gt; tribool operator&amp;&amp;( tribool b, RHS&amp;&amp; rhs, int ) 这样的东西,或者我们可以使用其他语法来指示不糟糕的“替代重载语义”(建议?)。那么rhs 将是由&amp;&amp; 子句右侧的语言(使用[&amp;] 捕获)隐式创建的lambda。在&amp;&amp; 重载中,我们可以选择评估它(使用())或不评估它,从而允许短路样式逻辑。
    • 重载的逻辑运算符没有获得从左到右的求值顺序,而成员函数却有原因吗?
    • @Präriewolf 成员函数也不行!
    • @jrok 所以不能保证第二个条件总是按那个顺序检查?
    • 从左到右的顺序由 1) 内置逻辑运算符(&amp;&amp;||)、2) 保证条件运算符(首先是 ? 左侧的操作数,然后是其余的一个),3) 内置逗号运算符,4) 在大括号初始化列表中( { })。我认为这涵盖了一切。其他地方的顺序是未指定的。
    猜你喜欢
    • 1970-01-01
    • 2014-12-02
    • 2012-09-26
    • 2021-02-20
    • 2011-06-09
    • 2011-08-06
    • 2019-10-26
    • 1970-01-01
    • 2012-01-08
    相关资源
    最近更新 更多