将临时对象转换为非const引用时出错

这是一个关于using temporary stringstream object的问题的可复制示例:

#include <sstream>                     
#include <string>
#include <iostream>

using namespace std;

std::string transform(std::string);

int main()
{
    int i{};
    cout << transform( static_cast<stringstream &>(stringstream() << i).str() );
}

在MacOS High Sierra下尝试使用 clang版本9.0.0 进行编译时,出现以下错误:

$ clang++ -std=c++11 x.cc -c
x.cc:12:24: error: non-const lvalue reference to type 'basic_stringstream<...>' cannot bind to a temporary of type 'basic_stringstream<...>'
    cout << transform( static_cast<stringstream &>(stringstream() << i).str() );
                       ^                           ~~~~~~~~~~~~~~~~~~~
1 error generated.

在同一台机器上(以及在Linux上)使用g ++ 9.2.0时,一切都可以正常编译。

似乎将转换从stringstream &更改为const stringstream &或转换为stringstream &&可以解决问题。

问题是这是编译器错误还是clang在某些标准规则上更严格?

mario_l 回答:将临时对象转换为非const引用时出错

是的,我认为这是libc ++中的错误。

根据[ostream.rvalue],有一个重载:

template<class charT,class traits,class T>
  basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&& os,const T& x);

But libc++ implements this similar to

template <class _Stream,class _Tp>
enable_if_t</*...*/,_Stream&&>
operator<<(_Stream&& __os,const _Tp& __x)
{
    // ...
}

如果将流右值与operator<<一起使用,则该实现使重载比ostream的类<<的重载解析度更好,而标准中的签名不会,当它应该返回左值引用时,它也会返回右值引用。根据标准引号,它还返回与传递给它的类型相同的引用,同时应返回对其ostream基类的引用。

右值引用不能绑定到非常量左值引用,因此会出错。

已经报告了该错误here,并且存在关于行为here的公开LWG问题,这似乎暗示着将来可能会对该标准进行调整以强制执行libc ++的当前行为。 / p>

,

答案是libstdc ++和libc ++之间的ostream插入的不同实现。

实现几乎相同,但是libc ++实现中包含以下代码(https://github.com/llvm/llvm-project/blob/master/libcxx/include/ostream):

template <class _Stream,class _Tp>
inline _LIBCPP_INLINE_VISIBILITY
typename enable_if
<
    !is_lvalue_reference<_Stream>::value &&
    is_base_of<ios_base,_Stream>::value,_Stream&&
>::type
operator<<(_Stream&& __os,const _Tp& __x)
{
    __os << __x;
    return _VSTD::move(__os);
}

这将抓取您原位创建的右值strstream并返回一个右值引用无法绑定到的右值。

另一方面,libstdc ++ implementation具有以下特点:

 template<typename _Ostream>
    using __rvalue_ostream_type =
      typename __is_convertible_to_basic_ostream<
    _Ostream>::__ostream_type;


  template<typename _Ostream,typename _Tp>
    inline
    typename enable_if<__and_<__not_<is_lvalue_reference<_Ostream>>,__is_convertible_to_basic_ostream<_Ostream>,__is_insertable<
                __rvalue_ostream_type<_Ostream>,const _Tp&>>::value,__rvalue_ostream_type<_Ostream>>::type
    operator<<(_Ostream&& __os,const _Tp& __x)
    {
      __rvalue_ostream_type<_Ostream> __ret_os = __os;
      __ret_os << __x;
      return __ret_os;

魔术之后的__rvalue_ostream_type不是r值引用。这样,代码即可编译。

以上是libstdc ++中的错误,可以作为错误报告提交。

本文链接:https://www.f2er.com/2926122.html

大家都在问