dutt
dutt

Reputation: 8209

Reading from const std::vector<char> via std::istream

I'm trying to read from a const std::vector to an std::istream, but everything I've tried runs into the problem with const.

This version compiles perfectly:

#include <vector>
#include <iostream>

template<typename CharT = char, typename TraitsT = std::char_traits<CharT> >
class vectorbuf : public std::basic_streambuf<CharT, TraitsT> {
public:
    vectorbuf(std::vector<char>& v) {
        this->setg(v.data(), v.data(), v.data()+v.size());
    }
};

void doStuff(std::vector<char>& v) {
    vectorbuf<> vbuff(v);
    std::istream s(&vbuff);
}

int main(int argc, char** argv) {
    std::vector<char> v = {'a', 'b', 'c'};
    doStuff(v);
    return 0;
}

while this produces errors:

#include <vector>
#include <iostream>

template<typename CharT = char, typename TraitsT = std::char_traits<CharT> >
class const_vectorbuf : public std::basic_streambuf<CharT, TraitsT> {
public:
    const_vectorbuf(const std::vector<char>& v) {
        this->setg(v.data(), v.data(), v.data()+v.size());
    }
};

void const_doStuff(const std::vector<char>& v) {
    const_vectorbuf<const char> vbuff(v);
    //std::istream s(&vbuff); With this commented out I get the error below
}

int main(int argc, char** argv) {
    std::vector<char> v = {'a', 'b', 'c'};
    const_doStuff(v);
    return 0;
}

And I'm not sure how to fix it.

The error:

In file included from /usr/include/c++/4.8/ios:40:0,
                 from /usr/include/c++/4.8/ostream:38,
                 from /usr/include/c++/4.8/iostream:39,
                 from vector_stream.cpp:2:
/usr/include/c++/4.8/bits/char_traits.h: In instantiation of ‘static void __gnu_cxx::char_traits<_CharT>::assign(__gnu_cxx::char_traits<_CharT>::char_type&, const char_type&) [with _CharT = const char; __gnu_cxx::char_traits<_CharT>::char_type = const char]’:
/usr/include/c++/4.8/bits/streambuf.tcc:67:63:   required from ‘std::streamsize std::basic_streambuf<_CharT, _Traits>::xsgetn(std::basic_streambuf<_CharT, _Traits>::char_type*, std::streamsize) [with _CharT = const char; _Traits = std::char_traits<const char>; std::streamsize = long int; std::basic_streambuf<_CharT, _Traits>::char_type = const char]’
vector_stream.cpp:36:1:   required from here
/usr/include/c++/4.8/bits/char_traits.h:93:14: error: assignment of read-only reference ‘__c1’
       { __c1 = __c2; }
              ^
In file included from /usr/include/c++/4.8/vector:60:0,
                 from vector_stream.cpp:1:
/usr/include/c++/4.8/bits/stl_algobase.h: In instantiation of ‘_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = const char*; _OI = const char*]’:
/usr/include/c++/4.8/bits/stl_algobase.h:428:38:   required from ‘_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = const char*; _OI = const char*]’
/usr/include/c++/4.8/bits/stl_algobase.h:460:17:   required from ‘_OI std::copy(_II, _II, _OI) [with _II = const char*; _OI = const char*]’
/usr/include/c++/4.8/bits/char_traits.h:192:39:   required from ‘static __gnu_cxx::char_traits<_CharT>::char_type* __gnu_cxx::char_traits<_CharT>::copy(__gnu_cxx::char_traits<_CharT>::char_type*, const char_type*, std::size_t) [with _CharT = const char; __gnu_cxx::char_traits<_CharT>::char_type = const char; std::size_t = long unsigned int]’
/usr/include/c++/4.8/bits/streambuf.tcc:56:50:   required from ‘std::streamsize std::basic_streambuf<_CharT, _Traits>::xsgetn(std::basic_streambuf<_CharT, _Traits>::char_type*, std::streamsize) [with _CharT = const char; _Traits = std::char_traits<const char>; std::streamsize = long int; std::basic_streambuf<_CharT, _Traits>::char_type = const char]’
vector_stream.cpp:36:1:   required from here
/usr/include/c++/4.8/bits/stl_algobase.h:390:70: error: no matching function for call to ‘std::__copy_move<false, true, std::random_access_iterator_tag>::__copy_m(const char*&, const char*&, const char*&)’
                        _Category>::__copy_m(__first, __last, __result);
                                                                      ^
/usr/include/c++/4.8/bits/stl_algobase.h:390:70: note: candidate is:
/usr/include/c++/4.8/bits/stl_algobase.h:368:9: note: template<class _Tp> static _Tp* std::__copy_move<_IsMove, true, std::random_access_iterator_tag>::__copy_m(const _Tp*, const _Tp*, _Tp*) [with _Tp = _Tp; bool _IsMove = false]
         __copy_m(const _Tp* __first, const _Tp* __last, _Tp* __result)
         ^
/usr/include/c++/4.8/bits/stl_algobase.h:368:9: note:   template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/stl_algobase.h:390:70: note:   deduced conflicting types for parameter ‘_Tp’ (‘char’ and ‘const char’)
                        _Category>::__copy_m(__first, __last, __result);

So despite CharT being const char streambuf_type is still char, I've been looking and so far I haven't found a way to change that. The assignment __c1 = __c2 in char_traits I haven't had the time to even begin look at a way to solve yet.

Upvotes: 1

Views: 851

Answers (1)

Mooing Duck
Mooing Duck

Reputation: 66961

I feel quite certain that basic_streambuf requires it's first template to be not-const. Also, I think basic_streambuf requires write access, because the basic_streambuf manages both in and out, regardless of what you use it for in the end. You should probably also override some other members to cause writes to fail: sputbackc, sungetc, sputc, sputn, xsputn...

§ 27.2.2/2 In the classes of Clause 27, a template formal parameter with name charT represents a member of the set of types containing char, wchar_t, and any other implementation-defined character types that satisfy the requirements for a character on which any of the iostream components can be instantiated.

(emphsis mine) This rule is a little vague, but I'm pretty sure it clearly covers your case.

Upvotes: 1

Related Questions