【问题标题】:How to parse comma separated values with boost::program_options?如何使用 boost::program_options 解析逗号分隔值?
【发布时间】:2014-10-15 18:12:37
【问题描述】:

我需要使用boost::program_options 解析像-value=str1,str2,str3 这样的cmd。我找到了exactly the same question,但它不再工作了(使用 boost 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.

【问题讨论】:

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


    【解决方案1】:

    您必须使operator&gt;&gt; 可被发现。

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

    现在请注意,正在从命名空间 boost::detail(来自 Boost Lexicalcast 库)内的某处调用流式运算符。

    它使用依赖于参数的查找来选择重载。 ADL 意味着与参数类型关联的命名空间指示应在哪些命名空间中搜索候选 operator>> 重载。¹

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

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

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

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

    【讨论】:

      【解决方案2】:

      由于某种原因,如果我只是删除命名空间 lli 并且它可以按预期工作..

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-29
        • 2016-06-22
        • 2013-09-01
        • 1970-01-01
        • 2017-08-29
        • 1970-01-01
        • 2020-09-22
        • 2023-01-11
        相关资源
        最近更新 更多