【问题标题】:Is libstdc++ wrong to reject assignment of volatile rvalue to std::ignore?libstdc++ 拒绝将 volatile 右值分配给 std::ignore 是错误的吗?
【发布时间】:2016-06-20 22:14:02
【问题描述】:

我注意到 libstdc++ 的 std::ignore 实现采用 const T& 参数,该参数不能绑定到 volatile 右值。因此以下代码无法编译:

#include <tuple>
#include <utility>
struct C {};
using VC = C volatile;
int main() {
    std::tuple<VC> t;
    std::tie(std::ignore) = std::move(t);
}

(http://coliru.stacked-crooked.com/a/7bfc499c1748e59e)

这是否违反了标准,或者是否存在导致这种未定义行为的条款?

【问题讨论】:

  • 你为什么要首先使用volatile?它禁用优化,不会使事情线程安全。我不明白你为什么要这样做......
  • @JesperJuhl 因为它就在那里
  • 不是个好理由。代码可以更改。
  • @JesperJuhl stackoverflow.com/questions/72552/why-does-volatile-exist 此外,语言律师问题有权询问无意义的(或至少是奇怪的)极端案例,将其视为一项运动。
  • 这种情况并非“无稽之谈”。这是一个证明问题的最小案例。如果这是一个显示 volatile 有效使用的真实示例,人们会抱怨它不是 MCVE。

标签: c++ c++11 g++ tuples language-lawyer


【解决方案1】:

我不是语言律师,所以我将尽可能直接地回答这个问题。

ignore 可以在tuple 的概要中找到tuple.general,如下所示:

// [tuple.creation], tuple creation functions:
const unspecified ignore;

如您所见,libstdc++ 实现定义 ignore 如下:

  // A class (and instance) which can be used in 'tie' when an element
  // of a tuple is not required
  struct _Swallow_assign
  {
    template<class _Tp>
      const _Swallow_assign&
      operator=(const _Tp&) const
      { return *this; }
  };

libc++ 版本是这样定义的:

template <class _Up>
struct __ignore_t
{
    template <class _Tp>
        _LIBCPP_INLINE_VISIBILITY
        const __ignore_t& operator=(_Tp&&) const {return *this;}
};

因此,它在 libc++ 中编译。现在可以在 [tuple.creation] 中找到std::tie 的定义:

返回:tuple&lt;Types&amp;...&gt;(t...)。当t 中的参数是 ignore,给对应的元组元素赋值有 没有效果。

这并没有说明ignore 本身的任何内容,所以我将把它归结为未指定 的行为。您可以通过遗漏来争辩它是 undefined 行为,但这可能会延长它。

【讨论】:

  • 我不确定我是否理解。这不是很好地指定了行为,以至于我发布的代码应该没有效果,这似乎没有给实现许可来拒绝代码吗?
  • @Brian No effect 本身未指定。 std::tie 没有 effects 子句。 ignore 中的 operator= 除了 return *this 什么都不做,所以是无操作,完全符合无影响的定义。无论哪种方式,代码都会因为库的实现方式而被拒绝,而不是因为违反了std::tie 下的任何条款。
  • 不,不是说函数std::tie没有效果;它说“为相应的元组元素分配任何值都没有效果”。
  • @Brian 我不是这么说的。我说它没有 effects 子句,它有时存在,有时不存在。目前唯一的措辞是no effects。所以接下来唯一的事情就是纯粹的猜测。 (我在上面编辑了我的评论,以防你认为我的意思是 tie 是无操作的)。
【解决方案2】:

评论:

// g++ 4.8.4
int main() {
    volatile int vi;
    std::ignore = vi;

    // error: no match for ‘operator=’ (
    //     operand types are ‘const std::_Swallow_assign’
    //     and ‘std::remove_reference<volatile int&>::type {aka volatile int}’
    // )
    // std::ignore = std::move(vi);

    // However this compiles:
    volatile int&& vir = std::move(vi);
    std::ignore = vir;
}

【讨论】:

    猜你喜欢
    • 2012-05-16
    • 2014-11-25
    • 1970-01-01
    • 2020-07-06
    • 2022-01-14
    • 1970-01-01
    • 2017-12-02
    • 2019-10-04
    • 1970-01-01
    相关资源
    最近更新 更多