2016-10-18 20 views
4

В моем API у меня есть функция, которая возвращает std::istringstream.
std::istringstream class не скопирован, но поддерживает перемещение так на соответствующем компиляторе, нет проблем с возвратом локального std::istringstream.Обходной способ для возврата непокрытого объекта без перемещения ctor

Тем не менее, на gcc 4.9 есть no support для перемещения std::istringstream. Есть ли способ обхода, который я могу использовать, что std::istringstream без изменения API с точки зрения пользователя?

Обходное решение, предложенное here, с использованием unique_ptr<std::istringstream> изменит семантику API.

+4

Я не понимаю, как вы можете иметь обходной путь, если вы не можете изменить тип возвращаемого значения. – NathanOliver

+0

Ну, скажем, я беру результат с помощью 'auto' (или просто использую его как временный), чтобы вы могли вернуть что-то еще. Теперь я думаю, что можно создать оболочку с тем же интерфейсом и вернуть ее. –

+0

Обертка затронет ту же проблему. Вы не можете переместить поток в оболочку, и вы не можете его скопировать, так как вы получаете оболочку из этой функции? – NathanOliver

ответ

0

Отвечая на мой собственный вопрос для полноты и в будущем.

Цель состояла в том, чтобы найти обходной путь для GCC (< 5) ошибки где std::istringstream не обеспечивает перемещение CTOR, который будет работать в тех случаях, когда я хочу, чтобы вернуть не-копируемые и (bugly-) неподвижный поток ,
Как упоминалось в комментариях, я могу на самом деле изменить свою сигнатуру функции (по крайней мере, на gcc < 5), чтобы вернуть прокси-объект, который позволяет копировать или перемещать, не изменяя API для кода, используемого для новых/других компиляторов.

Идея предложена и реализована коллегой, чтобы создать прокси-объект вокруг std::istringstream который обеспечивает аналогичный API, но и обеспечивает копирование-CTOR, который вручную создает и инициализирует новый внутренний 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 
0

Если вы не можете переместить std::istringstream, об этом не обойтись.

Если объект не копируется и не движется, вы не можете вернуть его по значению. Если вы хотите поддерживать новые функции, вам лучше получить новый компилятор для них.

В мясном вы можете вернуть unique_ptr. Если вы действительно хотите вернуться по значению, вы можете вернуть подвижную оболочку, содержащую std::unique_ptr<std::istringstream> и предоставить тот же интерфейс, что и istringstream. Однако это также влияет на тип возврата.


Возможно, возникает соблазн вернуться по ссылке rvalue. Вот что вы можете сделать:

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 менее подвержен влиянию. Кроме этого, я не знаю обходного пути.

0

Путь возврата класс без перемещения/копирования конструктор использовать оператор возврата с рамно-Init-лист:

class C { 
    C() = default; 
    C(const C&) = delete; 
    C(C&&) = delete; 
}; 

C make_C() { return {}; } 

int main() { 
    C&& c = make_C(); 
} 

Demo

К сожалению, только не явный конструктор считаются для этого инициализация и std::istringstream имеют явный конструктор.

Один из способов заключается в создании суб-класса с не явного конструктора:

struct myIStringStream : std::istringstream 
{ 
    myIStringStream() = default; 
}; 

myIStringStream make_istringstream() 
{ 
    return {}; 
} 

int main() 
{ 
    std::istringstream&& iss = make_istringstream(); 
} 

Demo

 Смежные вопросы

  • Нет связанных вопросов^_^