如何用boost :: program_options解析逗号分隔值?

时间:2014-10-15 18:12:37

标签: boost command-line boost-program-options

我需要使用-value=str1,str2,str3解析像boost::program_options这样的cmd。我发现exactly the same question但它不再起作用了(使用1.55和1.56提升)。

我试图定义自己的类和映射器,但没有运气:

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;
}

错误讯息:

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.

2 个答案:

答案 0 :(得分:4)

您必须使operator>>可被发现。

因为它需要在std::istream&的左侧操作,所以不能在“拥有”类中声明它;但作为一个自由函数,您需要使用命名空间查找,以便代码找到流操作符。

现在请注意,从名称空间boost::detail内部(来自Boost Lexicalcast库)调用流操作符。

它使用参数依赖查找来选择重载。 ADL意味着与参数类型相关联的名称空间指示应该为候选运算符搜索哪些名称空间&gt;&gt; overloads.¹

这意味着查找将搜索名称空间std(由于std::istream参数)以及lli(由于第二个参数类型)。请注意,如果任何参数 types 本身使用模板参数类型,则定义 的命名空间也包含在查找中。

如你所说,你可以解决这个问题

  • 不使用命名空间。
  • 或者,您可以定义运算符&gt;&gt; lli命名空间内的重载: Live On Coliru
  • 或者,在类中声明它(作为友元静态函数,将被视为在包含的命名空间中声明): Live On Coliru

¹它适用于非操作员免费功能,但

答案 1 :(得分:0)

由于某些原因,如果我只删除命名空间lli并且它按预期工作,它可以被编译(没有上面的错误)。