1

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.

dutt
  • 7,909
  • 11
  • 52
  • 85
  • @ildjarn: I don't think it is actually. My memory says it's not, and GCC agrees: http://coliru.stacked-crooked.com/a/d98e94408a0b7579 – Mooing Duck Aug 04 '14 at 20:25
  • It's not, the first example compiles perfectly for me. What I'm really trying to do is to get the contents from the vector into a bytes field of a google protobuf message. – dutt Aug 04 '14 at 20:27
  • @MooingDuck : Indeed, you're correct; that being said, I still don' see the intention of this code, nor how the first example compiles correctly... – ildjarn Aug 04 '14 at 20:29
  • 1
    To create an istream that reads from a vector. http://stackoverflow.com/a/8815308 – dutt Aug 04 '14 at 20:31
  • Ah, wow, I totally misread the code. I'll be on my way now, sorry for the noise. – ildjarn Aug 04 '14 at 20:33

1 Answers1

1

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.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • Ah, that does sound reasonable. This is probably the first time in my programming career I've run straight into the standard like this. Progress!...or something ;) – dutt Aug 04 '14 at 20:47
  • One cannot get rid of the error by overriding `xsputn` and the company. About the only thing one can reasonably do is `const_cast`ing the data pointers for `setg` (and not using `const char` as a template argument). – n. m. could be an AI Aug 04 '14 at 20:49
  • From what I've learnt if you need a const cast something larger is wrong with the design. – dutt Aug 04 '14 at 20:53
  • @n.m.: I had intended to say that overriding those should be done _in addition_ to solving the problem, as they'll help prevent other problems. – Mooing Duck Aug 04 '14 at 21:04
  • @dutt: You're absolutely right about the `const_cast`, but unfortunately, the error in the design is `basic_streambuf` being used for both input and output streams, when they should have instead been separate. Most people agree the internals (and some externals!) of IOstream are poorly designed, and this is one of the reasons. – Mooing Duck Aug 04 '14 at 21:05
  • Something *is* wrong with the design of iostreams. Lots of things actually. – n. m. could be an AI Aug 05 '14 at 02:26
  • @MooingDuck Ah, thanks for the elaboration. And since everything must be backwards compatible I assume there's no work to improve the iostreams library? Or maybe replace it with a new header? – dutt Aug 05 '14 at 06:51
  • @dutt: It turns out that a generic formatting library that handles all locales is incredibly hard, so nobody has suggested a viable replacement to the C++ committee yet. – Mooing Duck Aug 05 '14 at 16:15
  • Ah yea, should've seen that one coming :) – dutt Aug 05 '14 at 20:20