在我的API中,我有一个返回std::istringstream
的函数
std::istringstream
class是不可复制的,但支持在符合标准的编译器上移动,返回本地std::istringstream
没有问题。
但是,在gcc 4.9上,移动std::istringstream
有no support。
我是否可以使用std::istringstream
而无需从用户的角度更改API?
使用unique_ptr<std::istringstream>
的解决方法建议here将更改API的语义。
答案 0 :(得分:0)
如果你无法移动std::istringstream
,那就没有太多办法了。
如果对象不可复制且不可移动,则无法按值返回。 如果您想支持新功能,最好为这些功能获得新的编译器。
在meatime中,你可以返回unique_ptr
。如果你真的渴望按值返回,你可以返回一个包含std::unique_ptr<std::istringstream>
的可移动包装器,并提供与istringstream相同的接口。但是,这也会影响返回类型。
通过右值参考返回可能很诱人。这是你可以做的:
struct MyApiClass {
std::istringstream&& get_stream() {
return std::move(*_stream);
}
private:
std::unique_ptr<std::istringstream> _stream;
};
然后,使用旧的编译器,您可以像这样使用它:
std::istringstream&& stream = myApiClass.get_stream();
// use stream as long as myApiClass exists
使用新编译器的人将能够像这样使用它:
std::istringstream stream = myApiClass.get_stream();
// use stream normally
这是api受影响较小的方式。除此之外,我不知道任何解决方法。
答案 1 :(得分:0)
没有移动/复制构造函数返回类的方法是使用带有braced-init-list的return语句:
class C {
C() = default;
C(const C&) = delete;
C(C&&) = delete;
};
C make_C() { return {}; }
int main() {
C&& c = make_C();
}
不幸的是,只考虑非显式构造函数进行初始化,std::istringstream
具有显式构造函数。
一种解决方法是使用非显式构造函数创建子类:
struct myIStringStream : std::istringstream
{
myIStringStream () = default;
};
myIStringStream make_istringstream()
{
return {};
}
int main()
{
std::istringstream&& iss = make_istringstream();
}
答案 2 :(得分:0)
回答我自己的问题,以便完整和将来参考。
目标是为gcc(&lt; 5)错误找到解决方法,其中std::istringstream
没有提供移动ctor,以便在我想要返回联合国的情况下工作-copyable和(bugly-)不可移动的流
正如评论中所提到的,我实际上可以更改我的函数签名(至少在gcc&lt; 5上)以返回允许复制或移动的代理对象,而无需更改新/其他编译器上使用的代码的API。
同事建议并实施的想法是围绕std::istringstream
创建一个提供类似API的代理对象,同时提供一个手动创建和初始化新内部std::istringstream
的副本。来自复制的流。此代理仅用于违规编译器。
自然栖息地的代码是here 这是相关部分:
#if !defined(__GNUC__) || (__GNUC__ >= 5)
using string_stream = std::istringstream;
#else
// Until GCC 5, istringstream did not have a move constructor.
// stringstream_proxy is used instead, as a workaround.
class stringstream_proxy
{
public:
stringstream_proxy() = default;
// Construct with a value.
stringstream_proxy(std::string const& value) :
stream_(value)
{}
// Copy constructor.
stringstream_proxy(const stringstream_proxy& other) :
stream_(other.stream_.str())
{
stream_.setstate(other.stream_.rdstate());
}
void setstate(std::ios_base::iostate state) { stream_.setstate(state); }
// Stream out the value of the parameter.
// If the conversion was not possible, the stream will enter the fail state,
// and operator bool will return false.
template<typename T>
stringstream_proxy& operator >> (T& thing)
{
stream_ >> thing;
return *this;
}
// Get the string value.
std::string str() const { return stream_.str(); }
std::stringbuf* rdbuf() const { return stream_.rdbuf(); }
// Check the state of the stream.
// False when the most recent stream operation failed
operator bool() const { return !!stream_; }
~stringstream_proxy() = default;
private:
std::istringstream stream_;
};
using string_stream = stringstream_proxy;
#endif