I need to parse cmd like -value=str1,str2,str3
using boost::program_options
. I've found exactly the same question but it's not working anymore (with boost 1.55 and 1.56).
I've tried to define my own class and mapper but no luck:
namespace po = boost::program_options;
desc.add_options()
("mattr", po::value<lli::CommaSeparatedVector>(&MAttrs), "Target specific attributes (-mattr=help for details)");
namespace lli {
class CommaSeparatedVector
{
public:
// comma separated values list
std::vector<std::string> values;
};
}
void tokenize(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters = ",")
{
// Skip delimiters at beginning.
std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
// Find first non-delimiter.
std::string::size_type pos = str.find_first_of(delimiters, lastPos);
while (std::string::npos != pos || std::string::npos != lastPos) {
// Found a token, add it to the vector.
tokens.push_back(str.substr(lastPos, pos - lastPos));
// Skip delimiters.
lastPos = str.find_first_not_of(delimiters, pos);
// Find next non-delimiter.
pos = str.find_first_of(delimiters, lastPos);
}
}
// mapper for "lli::CommaSeparatedVector"
std::istream& operator>>(std::istream& in, lli::CommaSeparatedVector &value)
{
std::string token;
in >> token;
tokenize(token, value.values);
return in;
}
Error message:
In file included from /softdev/boost-1.56/include/boost/program_options.hpp:15:
In file included from /softdev/boost-1.56/include/boost/program_options/options_description.hpp:13:
In file included from /softdev/boost-1.56/include/boost/program_options/value_semantic.hpp:14:
/softdev/boost-1.56/include/boost/lexical_cast.hpp:379:13: error: implicit instantiation of undefined template
'boost::STATIC_ASSERTION_FAILURE<false>'
BOOST_STATIC_ASSERT_MSG((result_t::value || boost::has_right_shift<std::basic_istream<wchar_t>, T >::value),
^
/softdev/boost-1.56/include/boost/static_assert.hpp:36:48: note: expanded from macro 'BOOST_STATIC_ASSERT_MSG'
# define BOOST_STATIC_ASSERT_MSG( B, Msg ) BOOST_STATIC_ASSERT( B )
^
/softdev/boost-1.56/include/boost/static_assert.hpp:169:13: note: expanded from macro 'BOOST_STATIC_ASSERT'
sizeof(::boost::STATIC_ASSERTION_FAILURE< BOOST_STATIC_ASSERT_BOOL_CAST( __VA_ARGS__ ) >)>\
^
/softdev/boost-1.56/include/boost/lexical_cast.hpp:406:44: note: in instantiation of template class
'boost::detail::deduce_target_char_impl<boost::detail::deduce_character_type_later<lli::CommaSeparatedVector> >'
requested here
typedef BOOST_DEDUCED_TYPENAME deduce_target_char_impl< stage1_type >::type stage2_type;
^
/softdev/boost-1.56/include/boost/lexical_cast.hpp:564:59: note: in instantiation of template class
'boost::detail::deduce_target_char<lli::CommaSeparatedVector>' requested here
typedef BOOST_DEDUCED_TYPENAME boost::detail::deduce_target_char<Target>::type target_char_t;
^
/softdev/boost-1.56/include/boost/lexical_cast.hpp:2067:40: note: in instantiation of template class
'boost::detail::lexical_cast_stream_traits<std::__1::basic_string<char>, lli::CommaSeparatedVector>' requested here
BOOST_DEDUCED_TYPENAME stream_trait::char_type,
^
/softdev/boost-1.56/include/boost/lexical_cast.hpp:2289:20: note: in instantiation of template class
'boost::detail::lexical_converter_impl<lli::CommaSeparatedVector, std::__1::basic_string<char> >' requested here
return caster_type::try_convert(arg, result);
^
/softdev/boost-1.56/include/boost/lexical_cast.hpp:2316:41: note: in instantiation of function template specialization
'boost::conversion::detail::try_lexical_convert<lli::CommaSeparatedVector, std::__1::basic_string<char> >' requested
here
if (!boost::conversion::detail::try_lexical_convert(arg, result))
^
/softdev/boost-1.56/include/boost/program_options/detail/value_semantic.hpp:89:21: note: in instantiation of function
template specialization 'boost::lexical_cast<lli::CommaSeparatedVector, std::__1::basic_string<char> >' requested here
v = any(lexical_cast<T>(s));
^
/softdev/boost-1.56/include/boost/program_options/detail/value_semantic.hpp:167:13: note: in instantiation of function
template specialization 'boost::program_options::validate<lli::CommaSeparatedVector, char>' requested here
validate(value_store, new_tokens, (T*)0, 0);
^
/softdev/boost-1.56/include/boost/program_options/detail/value_semantic.hpp:182:33: note: in instantiation of member function
'boost::program_options::typed_value<lli::CommaSeparatedVector, char>::xparse' requested here
typed_value<T>* r = new typed_value<T>(v);
^
./lib_lli.cpp:480:23: note: in instantiation of function template specialization
'boost::program_options::value<lli::CommaSeparatedVector>' requested here
("mattr", po::value<lli::CommaSeparatedVector>(&MAttrs), "Target specific attributes (-mattr=help for details)");
^
/softdev/boost-1.56/include/boost/static_assert.hpp:87:26: note: template is declared here
template <bool x> struct STATIC_ASSERTION_FAILURE;
^
1 warning and 1 error generated.
You will have to make the
operator>>
discoverable.Because it needs to operate on a left-hand-side of
std::istream&
it cannot be declared in the "owning" class; But being a free function, you will need to employ namespace lookups in order for the code to find the streaming operator.Now note that the streaming operator is being called from somewhere inside namespace
boost::detail
(from the Boost Lexicalcast library).It uses argument dependent lookup to select the overload. ADL implies that the namespaces associated with the argument types indicate which namespaces should be searched for candidate operator>> overloads.¹
This means that the lookup will search namespace
std
(due to thestd::istream
argument) and alsolli
(due to the second argument type). Note that if any of the argument types itself uses a template argument type, the namespace(s) defining that are also included in the lookup.As you noted, you can get around this
lli
namespace: Live On Coliru¹ it works for non-operator free functions just the same, though
For some reason it can be compiled (no errors like above) if i just remove namespace lli and it works as expected ..