Use boost::tokenizer with boost::iterator_range - c++

I'm using boost::tokenizer to read a CSV-like file. I'm storing the the tokens in a std::vector. It works well, but I want to store only a boost::iterator for each token.
I tried:
#include <string>
#include <boost/tokenizer.hpp>
#include <boost/range/iterator_range.hpp>
typedef std::string::const_iterator string_iter;
typedef boost::iterator_range<string_iter> string_view;
int main(){
std::string line;
std::vector<string_view> contents;
boost::tokenizer<boost::escaped_list_separator<char>, string_iter, string_view> tok(line.begin(), line.end());
contents.assing(tok.begin(), tok.end());
}
But it fails to compile:
/usr/include/boost/token_functions.hpp: In instantiation of ‘bool
boost::escaped_list_separator::operator()(InputIterator&, InputIterator, Token&) [with
InputIterator = __gnu_cxx::__normal_iterator >; Token =
boost::iterator_range<__gnu_cxx::__normal_iterator > >; Char = char; Traits =
std::char_traits]’: /usr/include/boost/token_iterator.hpp:70:11:
required from ‘void boost::token_iterator::initialize() [with TokenizerFunc =
boost::escaped_list_separator; Iterator =
__gnu_cxx::__normal_iterator >; Type = boost::iterator_range<__gnu_cxx::__normal_iterator > >]’
/usr/include/boost/token_iterator.hpp:77:63: required from
‘boost::token_iterator::token_iterator(TokenizerFunc, Iterator, Iterator) [with
TokenizerFunc = boost::escaped_list_separator; Iterator =
__gnu_cxx::__normal_iterator >; Type = boost::iterator_range<__gnu_cxx::__normal_iterator > >]’ /usr/include/boost/tokenizer.hpp:86:53:
required from ‘boost::tokenizer::iter
boost::tokenizer::begin() const [with
TokenizerFunc = boost::escaped_list_separator; Iterator =
__gnu_cxx::__normal_iterator >; Type = boost::iterator_range<__gnu_cxx::__normal_iterator > >; boost::tokenizer::iter =
boost::token_iterator,
__gnu_cxx::__normal_iterator >, boost::iterator_range<__gnu_cxx::__normal_iterator > > >]’
/home/wichtounet/dev/gooda-to-afdo-converter/src/gooda_reader.cpp:58:37:
required from here /usr/include/boost/token_functions.hpp:187:16:
error: no match for ‘operator+=’ in ‘tok += (&
next)->__gnu_cxx::__normal_iterator<_Iterator,
_Container>::operator* >()’ /usr/include/boost/token_functions.hpp:193:11: error: no match for
‘operator+=’ in ‘tok += (&
next)->__gnu_cxx::__normal_iterator<_Iterator,
_Container>::operator* >()’ /usr/include/boost/token_functions.hpp: In instantiation of ‘void
boost::escaped_list_separator::do_escape(iterator&,
iterator, Token&) [with iterator = __gnu_cxx::__normal_iterator >; Token =
boost::iterator_range<__gnu_cxx::__normal_iterator > >; Char = char; Traits =
std::char_traits]’:
/usr/include/boost/token_functions.hpp:176:11: required from ‘bool
boost::escaped_list_separator::operator()(InputIterator&, InputIterator, Token&) [with
InputIterator = __gnu_cxx::__normal_iterator >; Token =
boost::iterator_range<__gnu_cxx::__normal_iterator > >; Char = char; Traits =
std::char_traits]’ /usr/include/boost/token_iterator.hpp:70:11:
required from ‘void boost::token_iterator::initialize() [with TokenizerFunc =
boost::escaped_list_separator; Iterator =
__gnu_cxx::__normal_iterator >; Type = boost::iterator_range<__gnu_cxx::__normal_iterator > >]’
/usr/include/boost/token_iterator.hpp:77:63: required from
‘boost::token_iterator::token_iterator(TokenizerFunc, Iterator, Iterator) [with
TokenizerFunc = boost::escaped_list_separator; Iterator =
__gnu_cxx::__normal_iterator >; Type = boost::iterator_range<__gnu_cxx::__normal_iterator > >]’ /usr/include/boost/tokenizer.hpp:86:53:
required from ‘boost::tokenizer::iter
boost::tokenizer::begin() const [with
TokenizerFunc = boost::escaped_list_separator; Iterator =
__gnu_cxx::__normal_iterator >; Type = boost::iterator_range<__gnu_cxx::__normal_iterator > >; boost::tokenizer::iter =
boost::token_iterator,
__gnu_cxx::__normal_iterator >, boost::iterator_range<__gnu_cxx::__normal_iterator > > >]’
/home/wichtounet/dev/gooda-to-afdo-converter/src/gooda_reader.cpp:58:37:
required from here /usr/include/boost/token_functions.hpp:130:9:
error: no match for ‘operator+=’ in ‘tok += '\012'’
/usr/include/boost/token_functions.hpp:134:9: error: no match for
‘operator+=’ in ‘tok += (&
next)->__gnu_cxx::__normal_iterator<_Iterator,
_Container>::operator* >()’ /usr/include/boost/token_functions.hpp:138:9: error: no match for
‘operator+=’ in ‘tok += (&
next)->__gnu_cxx::__normal_iterator<_Iterator,
_Container>::operator* >()’ /usr/include/boost/token_functions.hpp:142:9: error: no match for
‘operator+=’ in ‘tok += (&
next)->__gnu_cxx::__normal_iterator<_Iterator,
_Container>::operator* >()’
I also simply tried to compute the two iterators by myself using the boost::token_iterator, but I haven't been successful so far.
Is there a solution to get only the iterator range of each token instead of the string in order to save some performances ?

This can't work. The tokenizer expects a type (the third template argument) which can be appended with the results of the tokenizer function. Specifically, it must provide the operator += ( tokenizer<...>::iterator::value_type ). The code snippet below should take you a step further, though I am not sure if it's worth the effort...
#include <string>
#include <boost/tokenizer.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>
#include <cstddef>
typedef std::string::const_iterator string_iter;
typedef boost::iterator_range<string_iter> string_view;
// a constant size character buffer, skips anything beyond CSize...
template< std::size_t CSize >
class assignable_view {
std::size_t m_size;
char m_buffer[CSize];
friend std::ostream& operator << (std::ostream& p_out, assignable_view const & p_view)
{
if (p_view.m_size > 0u) {
std::copy(p_view.m_buffer, p_view.m_buffer + p_view.m_size, std::ostream_iterator<char>(p_out));
}
return p_out;
}
public:
template <class TIter>
void operator += (TIter p_input)
{
if (m_size < CSize) {
m_buffer[m_size++] = p_input;
}
}
assignable_view()
: m_size(0u) {}
};
int main(){
std::string line
= "Field 1,\"putting quotes around fields, allows commas\",Field 3";
std::vector<string_view> contents;
boost::tokenizer<
boost::escaped_list_separator<char>,
string_iter,
assignable_view<11>
> tok(line.begin(), line.end());
for (auto const & t_s : tok) {
std::cout << t_s << std::endl;
}
//contents.assing(tok.begin(), tok.end());
}

Ah! You'd need an include:
#include <iostream>
#include <boost/tokenizer.hpp>
#include <boost/range/iterator_range.hpp>
#include <string>
int main()
{
std::string line;
typedef std::string::const_iterator string_iter;
typedef boost::iterator_range<string_iter> string_view;
boost::tokenizer<boost::escaped_list_separator<char>, string_iter, string_view> tok(line.begin(), line.end());
}
compiles fine

Related

C++ checking if an element is in my vector but getting failed to convert errors from eclipse

So below is my code. I am giving it several inputs but the important one is symbol and symbolList. symbolList is a 2D vector of strings. and the intent here is to check if symbol exists in symbolList and I am using the example from here: https://www.techiedelight.com/check-vector-contains-given-element-cpp/
Here is the code, error is on the if statement.
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <string.h>
#include "windows.h"
#include <vector>
#include <chrono>
#include <algorithm>
using namespace std;
bool check_input(string &orderID, char buysell, string &symbol, int &qty, string &error, vector<vector<string>> &symbolList) {
error="None";
//omitted some irrelevant stuff
if (std::find(symbolList.begin(), symbolList.end(), symbol) != symbolList.end()) {
error= "wrong symbol";
return false;
}
return true;
}
But eclipse gives this error with my code and I don't see why:
could not convert 'std::find<__gnu_cxx::__normal_iterator<std::vector<std::basic_string<char> >*, std::vector<std::vector<std::basic_string<char> > > >, std::basic_string<char> >((& symbolList)->std::vector<std::vector<std::basic_string<char> > >::begin(), (& symbolList)->std::vector<std::vector<std::basic_string<char> > >::end(), (*(const std::basic_string<char>*)(& symbol)))' from '__gnu_cxx::__normal_iterator<std::vector<std::basic_string<char> >*, std::vector<std::vector<std::basic_string<char> > > >' to 'bool'
The compile error if I try to compile:
/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/include/c++/bits/predefined_ops.h: In instantiation of 'bool __gnu_cxx::__ops::_Iter_equals_val<_Value>::operator()(_Iterator) [with _Iterator = __gnu_cxx::__normal_iterator<std::vector<std::basic_string<char> >*, std::vector<std::vector<std::basic_string<char> > > >; _Value = const std::basic_string<char>]':
/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/include/c++/bits/stl_algo.h:120:14: required from '_RandomAccessIterator std::__find_if(_RandomAccessIterator, _RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::vector<std::basic_string<char> >*, std::vector<std::vector<std::basic_string<char> > > >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val<const std::basic_string<char> >]'
/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/include/c++/bits/stl_algo.h:161:23: required from '_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = __gnu_cxx::__normal_iterator<std::vector<std::basic_string<char> >*, std::vector<std::vector<std::basic_string<char> > > >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val<const std::basic_string<char> >]'
/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/include/c++/bits/stl_algo.h:3938:28: required from '_IIter std::find(_IIter, _IIter, const _Tp&) [with _IIter = __gnu_cxx::__normal_iterator<std::vector<std::basic_string<char> >*, std::vector<std::vector<std::basic_string<char> > > >; _Tp = std::basic_string<char>]'
../src/oncemore.cpp:37:60: required from here
/usr/lib/gcc/x86_64-pc-cygwin/9.3.0/include/c++/bits/predefined_ops.h:241:17: error: no match for 'operator==' (operand types are 'std::vector<std::basic_string<char> >' and 'const std::basic_string<char>')
You can find a string in a vector<string> but you are trying to find a string in a vector<vector<string>>, find can't do that.
It's not the only way to do it but my advice would be to use find in a loop.
for (const auto& row : symbolList) {
if (std::find(row.begin(), row.end(), symbol) != row.end()) {
error= "wrong symbol";
return false;
}
}
row is a reference to a vector<string> so you can find a string in that.

Why does std::pair<char, std::string> have problems with std::copy to ostream

Can someone explain why the code below won't compile if I remove the comments?
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include <iterator>
#include <algorithm>
std::pair<char, std::string> uncons(const std::string & s) {
std::string::size_type len = s.length();
if (len == 1) {
return std::make_pair(s[0], "");
} else if (len > 1) {
return std::make_pair(s[0], s.substr(1));
}
throw "Ooops, empty string";
}
std::ostream& operator<<(std::ostream & out, const std::pair<char, std::string> & p) {
if (p.second.length() > 0) {
out << "(\'" << p.first << "\', \"" << p.second << "\")";
}
return out;
}
int main(int argc, char ** argv) {
auto ans = uncons("G4143");
std::vector<std::pair<char, std::string> > vec{ans};
//If I remove the comments below the code fails to compile (GNU's g++14))
/*std::copy
(
vec.begin(),
vec.end(),
std::ostream_iterator<std::pair<char, std::string> >(std::cout, "\n")
);*/
return 0;
}
/*
In file included from /usr/include/c++/5/iterator:66:0,
from main.cpp:6:
/usr/include/c++/5/bits/stream_iterator.h: In instantiation of ‘std::ostream_iterator<_Tp, _CharT, _Traits>& std::ostream_iterator<_Tp, _CharT, _Traits>::operator=(const _Tp&) [with _Tp = std::pair<char, std::__cxx11::basic_string<char> >; _CharT = char; _Traits = std::char_traits<char>]’:
/usr/include/c++/5/bits/stl_algobase.h:340:18: required from ‘static _OI std::__copy_move<false, false, std::random_access_iterator_tag>::__copy_m(_II, _II, _OI) [with _II = std::pair<char, std::__cxx11::basic_string<char> >*; _OI = std::ostream_iterator<std::pair<char, std::__cxx11::basic_string<char> > >]’
/usr/include/c++/5/bits/stl_algobase.h:402:44: required from ‘_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = std::pair<char, std::__cxx11::basic_string<char> >*; _OI = std::ostream_iterator<std::pair<char, std::__cxx11::basic_string<char> > >]’
/usr/include/c++/5/bits/stl_algobase.h:438:45: required from ‘_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = __gnu_cxx::__normal_iterator<std::pair<char, std::__cxx11::basic_string<char> >*, std::vector<std::pair<char, std::__cxx11::basic_string<char> > > >; _OI = std::ostream_iterator<std::pair<char, std::__cxx11::basic_string<char> > >]’
/usr/include/c++/5/bits/stl_algobase.h:471:8: required from ‘_OI s/stream_iterator.h:198:13: note: ‘const std::pair<char,
....
std::__cxx11::basic_string<char> >’ is not derived from ‘const std::piecewise_constant_distribution<_RealType>’
*_M_stream << __value;
^
In file included from /usr/include/c++/5/random:51:0,
from /usr/include/c++/5/bits/stl_algo.h:66,
from /usr/include/c++/5/algorithm:62,
from main.cpp:7:
/usr/include/c++/5/bits/random.tcc:3160:5: note: candidate: template<class _RealType, class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::piecewise_linear_distribution<_RealType>&)
operator<<(std::basic_ostream<_CharT, _Traits>& __os,
^
/usr/include/c++/5/bits/random.tcc:3160:5: note: template argument deduction/substitution failed:
In file included from /usr/include/c++/5/iterator:66:0,
from main.cpp:6:
/usr/include/c++/5/bits/stream_iterator.h:198:13: note: ‘const std::pair<char, std::__cxx11::basic_string<char> >’ is not derived from ‘const std::piecewise_linear_distribution<_RealType>’
*_M_stream << __value;
*/
Now if I wrap the std::string part of the std::pair in a simple class (MyString) then everything works as expected. The code below compiles without issue and works as expected.
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include <iterator>
#include <algorithm>
class MyString {
public:
MyString(const std::string & s):str(s) {}
std::string str;
};
std::pair<char, MyString> uncons(const std::string & s) {
std::string::size_type len = s.length();
if (len == 1) {
return std::make_pair(s[0], MyString(""));
} else if (len > 1) {
return std::make_pair(s[0], MyString(s.substr(1)));
}
throw "Ooops, empty string";
}
std::ostream& operator<<(std::ostream & out, const std::pair<char, MyString> & p) {
if (p.second.str.length() > 0) {
out << "(\'" << p.first << "\', \"" << p.second.str << "\")";
}
return out;
}
int main(int argc, char ** argv) {
auto ans = uncons("G4143");
std::vector<std::pair<char, MyString> > vec{ans};
std::copy
(
vec.begin(),
vec.end(),
std::ostream_iterator<std::pair<char, MyString> >(std::cout, "\n")
);
return 0;
}
Can anyone shed some light on why this is happening? I modified my post as suggested and tried to enclose the error message in full but the forum won't allow the entire message the compiler barfed out.
As always, it's ADL.
operator<< is found via ADL, so in associated namespaces. Since the associated namespaces for std::string are merely namespace ::std (which declares it and the traits template parameter type argument) you would have to define the operator<< overload in that namespace.
In fact if you hack it and force your overload into the std namespace, it "works": http://coliru.stacked-crooked.com/a/7c2486ae963c2a64. Caution It is not legal to do this.
Once you wrap in a custom type, that type's declaring namespace participates in the ADL lookup.
Extra My usual take on providing custom streaming for primitives or non-user-defined types (optionally generically) is to create a manipulator to do it, see e.g. Template specialization (boost::lexical_cast)

Error when iterating through a map<std::string, std::string>

I have tried several ways of iterating over my "entries" map, but all of them produce the same lengthy error message.
dylan#Aspire-one:~$ g++ -std=c++11 dictionary.cpp
In file included from /usr/include/c++/4.8/map:60:0,
from dictionary.h:6,
from dictionary.cpp:1:
/usr/include/c++/4.8/bits/stl_tree.h: In instantiation of ‘void
std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare,
_Alloc>::_M_insert_unique(_II, _II) [with _InputIterator =
std::basic_string<char>; _Key = std::basic_string<char>; _Val =
std::pair<const std::basic_string<char>, std::basic_string<char> >;
_KeyOfValue = std::_Select1st<std::pair<const std::basic_string<char>,
std::basic_string<char> > >; _Compare = std::less<std::basic_string<char>
>; _Alloc = std::allocator<std::pair<const std::basic_string<char>,
std::basic_string<char> > >]’:
/usr/include/c++/4.8/bits/stl_map.h:226:11: required from
‘std::map<_Key, _Tp, _Compare, _Alloc>::map(_InputIterator,
_InputIterator) [with _InputIterator = std::basic_string<char>; _Key =
std::basic_string<char>; _Tp = std::basic_string<char>; _Compare =
std::less<std::basic_string<char> >; _Alloc =
std::allocator<std::pair<const std::basic_string<char>,
std::basic_string<char> > >]’
dictionary.h:11:66: required from here
/usr/include/c++/4.8/bits/stl_tree.h:1721:28: error: no match for
‘operator++’ (operand type is ‘std::basic_string<char>’)
for (; __first != __last; ++__first)
^
/usr/include/c++/4.8/bits/stl_tree.h:1722:29: error: no match for
‘operator*’ (operand type is ‘std::basic_string<char>’)
_M_insert_unique_(end(), *__first);
^
dylan#Aspire-one:~$
Here is my most recent code.
dictionary.cpp
#include "dictionary.h"
//I have included <string> <map> <iterator> "from dictionary.h"
bool dictionary::search_term(const std::string& term){
std::map<std::string, std::string>::iterator it;
for (it = entries.begin(); it != entries.end(); ++it){
if(it->first != term);
else return true;
}return false;
};
So the error is in "dictionary.h"?
dictionary.h
#ifndef DICTIONARY_H
#define DICTIONARY_H
#include <iterator>
#include <string>
#include <map>
class dictionary{
public:
dictionary(const std::string& title, const std::string& definition = "")
: entries(std::map<std::string, std::string>(title, definition)){;};
bool write_entry(const std::string& term, const std::string& definition = "");
bool define_term(const std::string& term, const std::string& definition);
bool erase_entry(const std::string& term);
bool search_term(const std::string& term);
private:
std::map<std::string, std::string> entries;
};
#endif//DICTIONARY_H
In the constructor, use brace initialization for the map:
dictionary(const std::string& title, const std::string& definition = "")
: entries{ {title, definition} } {;};
(EDIT: forgot one level of braces)
or set the element in the constructor body
dictionary(const std::string& title, const std::string& definition = "")
{
entries[title] = definition;
}
The problem is in the definition of the constructor of class dictionary. std::mapdoesn't have a constructor that takes a single key-value pair, so the easiest way to initialize with one pair is to use the universal initializer syntax. You'll need two pairs of braces, one for the list of key-value pairs, and one for the single pair you want to define:
dictionary(const std::string& title, const std::string& definition = "")
: entries(std::map<std::string, std::string>(title, definition)){;};
dictionary(const std::string& title, const std::string& definition = "")
: entries{ {title, definition} } {}

boost::algorithm::boyer_moore_search OO example

Please help me get a basic example of the object oriented boost::algorithm::boyer_moore_search interface working.
The procedural interface works for me, e.g this compiles and prints "pattern found":
#include <iostream>
#include <string>
#include <boost/algorithm/searching/boyer_moore.hpp>
int main() {
std::string corpus("hello world");
std::string pattern("hello");
if (corpus.end() != boost::algorithm::boyer_moore_search(corpus.begin(), corpus.end(),
pattern.begin(), pattern.end()))
{
std::cout << "pattern found" << std::endl;
}
return 0;
}
But the following using the object oriented interface gives a compiler error, e.g.
#include <iostream>
#include <string>
#include <boost/algorithm/searching/boyer_moore.hpp>
int main() {
std::string corpus("hello world");
std::string pattern("hello");
boost::algorithm::boyer_moore<std::string::const_iterator, std::string::const_iterator>
search(pattern.begin(), pattern.end());
if (corpus.end() != search(corpus.begin(), corpus.end()))
{
std::cout << "pattern found" << std::endl;
}
return 0;
}
This gives the following error, which is easily reproducible on ideone:
$ g++ test2.cpp
In file included from test2.cpp:3:0:
/usr/include/boost/algorithm/searching/boyer_moore.hpp: In instantiation of ‘class boost::algorithm::boyer_moore<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> > >’:
test2.cpp:10:14: required from here
/usr/include/boost/algorithm/searching/boyer_moore.hpp:104:39: error: no type named ‘skip_table_t’ in ‘class __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >’
typename traits::skip_table_t skip_;
^
/usr/include/boost/algorithm/searching/boyer_moore.hpp: In instantiation of ‘boost::algorithm::boyer_moore<patIter, traits>::boyer_moore(patIter, patIter) [with patIter = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >; traits = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >]’:
test2.cpp:10:44: required from here
/usr/include/boost/algorithm/searching/boyer_moore.hpp:63:50: error: using invalid field ‘boost::algorithm::boyer_moore<patIter, traits>::skip_’
suffix_ ( k_pattern_length + 1 )
^
/usr/include/boost/algorithm/searching/boyer_moore.hpp: In instantiation of ‘corpusIter boost::algorithm::boyer_moore<patIter, traits>::do_search(corpusIter, corpusIter) const [with corpusIter = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >; patIter = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >; traits = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >]’:
/usr/include/boost/algorithm/searching/boyer_moore.hpp:92:66: required from ‘corpusIter boost::algorithm::boyer_moore<patIter, traits>::operator()(corpusIter, corpusIter) const [with corpusIter = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >; patIter = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >; traits = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >]’
test2.cpp:12:60: required from here
/usr/include/boost/algorithm/searching/boyer_moore.hpp:133:27: error: using invalid field ‘boost::algorithm::boyer_moore<patIter, traits>::skip_’
k = skip_ [ curPos [ j - 1 ]];
^
I'm using gcc 4.8.2 and boost 1.54.
I'm trying to use the OO interface, because I am going to repeatedly search the same pattern in different corpuses and don't want to repeatedly calculate the same skip table.
The boyer_moore_search constructor takes a single template type parameter because both arguments to the constructor are the same type. You've provided two.
Change your declaration of search to:
boost::algorithm::boyer_moore<std::string::const_iterator>
search(pattern.begin(), pattern.end());
and it will work.

Is Adding boost::any in a boost::property_tree Possible?

I am trying to store a boost::any type to a boost property tree. Here is some runnable example:
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <sys/types.h>
#include <boost/any.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
int main()
{
boost::property_tree::ptree pTree_Root;
pTree_Root.put("sigRoot.property1", "value1");
pTree_Root.put("sigRoot.property2", "value2");
pTree_Root.put("sigRoot.property3", "value3");
std::vector<std::string> vecString;
for(int i = 0; i <= 5; i++) {
vecString.push_back("somestring");
}
boost::any anyVar = vecString;
pTree_Root.put("sigRoot.property4", anyVar);
std::stringstream ss;
boost::property_tree::json_parser::write_json(ss, pTree_Root);
std::string jsonString = ss.str();
jsonString.erase(std::remove(jsonString.begin(), jsonString.end(), '\n'), jsonString.end());
std::cout << jsonString << std::endl;
return 0;
}
This does not work, probably for the same reason boost::any is not serializable. But I see I am allowed to query anyVar.type(), but I have no idea what can be done with it. Is it possible to somehow use auto or something else to add the data to the property tree without explicitly coding a fixed number of known types here? C++11/C++0x methods are also welcome.
This is the error I get:
In file included from /usr/include/boost/property_tree/ptree.hpp:17:0,
from pTreeTest.cpp:8:
/usr/include/boost/property_tree/stream_translator.hpp: In static member function ‘static void boost::property_tree::customize_stream<Ch, Traits, E, Enabler>::insert(std::basic_ostream<_Ch, _Tr>&, const E&) [with Ch = char, Traits = std::char_traits<char>, E = boost::any, Enabler = void]’:
/usr/include/boost/property_tree/stream_translator.hpp:199:13: instantiated from ‘boost::optional<std::basic_string<Ch, Traits, Alloc> > boost::property_tree::stream_translator<Ch, Traits, Alloc, E>::put_value(const E&) [with Ch = char, Traits = std::char_traits<char>, Alloc = std::allocator<char>, E = boost::any]’
/usr/include/boost/property_tree/detail/ptree_implementation.hpp:795:54: instantiated from ‘void boost::property_tree::basic_ptree<Key, Data, KeyCompare>::put_value(const Type&, Translator) [with Type = boost::any, Translator = boost::property_tree::stream_translator<char, std::char_traits<char>, std::allocator<char>, boost::any>, Key = std::basic_string<char>, Data = std::basic_string<char>, KeyCompare = std::less<std::basic_string<char> >]’
/usr/include/boost/property_tree/detail/ptree_implementation.hpp:817:13: instantiated from ‘boost::property_tree::basic_ptree<K, D, C>& boost::property_tree::basic_ptree<Key, Data, KeyCompare>::put(const path_type&, const Type&, Translator) [with Type = boost::any, Translator = boost::property_tree::stream_translator<char, std::char_traits<char>, std::allocator<char>, boost::any>, Key = std::basic_string<char>, Data = std::basic_string<char>, KeyCompare = std::less<std::basic_string<char> >, boost::property_tree::basic_ptree<Key, Data, KeyCompare>::path_type = boost::property_tree::string_path<std::basic_string<char>, boost::property_tree::id_translator<std::basic_string<char> > >]’
/usr/include/boost/property_tree/detail/ptree_implementation.hpp:832:72: instantiated from ‘boost::property_tree::basic_ptree<K, D, C>& boost::property_tree::basic_ptree<Key, Data, KeyCompare>::put(const path_type&, const Type&) [with Type = boost::any, Key = std::basic_string<char>, Data = std::basic_string<char>, KeyCompare = std::less<std::basic_string<char> >, boost::property_tree::basic_ptree<Key, Data, KeyCompare>::path_type = boost::property_tree::string_path<std::basic_string<char>, boost::property_tree::id_translator<std::basic_string<char> > >]’
pTreeTest.cpp:26:47: instantiated from here
/usr/include/boost/property_tree/stream_translator.hpp:33:13: error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’
/usr/include/c++/4.6/ostream:581:5: error: initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char, _Traits = std::char_traits<char>, _Tp = boost::any]’
No. boost::any has no operator <<. You cannot use any in property_tree. anyVar.type() returns std::typeinfo, this class provides runtime information about type.
template<typename Type, typename Translator>
self_type & put(const path_type & path, const Type & value, Translator tr);
Set the value of the node at the given path to the supplied value, translated to the tree's data type. If the node doesn't exist, it is created, including all its missing parents.
You can create Translator and pass it to function put, since ptree is really basic_ptree<std::string, std::string> your translator should convert your any to string.
Simple example of translator
struct SimpleTranslator
{
public:
boost::optional<std::string> put_value(const boost::any& value)
{
if (value.type() == typeid(std::vector<std::string>))
{
std::stringstream ss;
std::vector<std::string> vec = boost::any_cast<std::vector<std::string>>(value);
std::copy(vec.begin(), vec.end(), std::ostream_iterator<std::string>(ss));
return ss.str();
}
return boost::optional<std::string>();
}
};
http://liveworkspace.org/code/275820c1becfb63deda4e4eed8524833