C++ 使用带有Boost程序选项的自定义类型

C++ 使用带有Boost程序选项的自定义类型,c++,boost,command-line-arguments,boost-program-options,C++,Boost,Command Line Arguments,Boost Program Options,我正在尝试使用Boost ProgramOptions解析配置文件以初始化我自己的类类型数据集(下面的代码) 我加入的选项如下: config_.add_options()("dataset", po::value<Dataset>()->required(),"Dataset"); 我想这提供了一些我想要的类型安全性,如: Dataset d(1); // Should be error Dataset d = Dataset::JAVA; // Should be fin

我正在尝试使用Boost ProgramOptions解析配置文件以初始化我自己的类类型数据集(下面的代码)

我加入的选项如下:

config_.add_options()("dataset", po::value<Dataset>()->required(),"Dataset");
我想这提供了一些我想要的类型安全性,如:

Dataset d(1); // Should be error
Dataset d = Dataset::JAVA; // Should be fine
double val = d; // Should be error
if(d == Dataset::SUMATRA) {} // should be fine
if(d == 3) {} // Should be error

模板化的
运算符T()
是编译器查找
运算符>
的原因和工作方式:

在boost的深处,有一些东西类似于
is>>some\u dataset
。由于它在boost名称空间中,而不是在您的名称空间中,编译器首先检查可访问的boost名称空间中是否有合适的运算符,或者在
istream
类中是否有成员运算符,这些运算符可以在不进行类型转换的情况下调用。显然没有。
作为第二种方法,它可以查看是否存在通过类型转换可以访问的此类运算符。输入“convert me to everything”(将我转换为所有内容)运算符,以及在错误消息中看到的
istream::operator>
的不同重载。重载接受不同类型的函数指针和streambuf指针,并且由于您的类可转换为这些类型中的任何一种,编译器不知道是否应将数据集转换为
streambuf*
或其他类型。
作为第三个选项,即当
操作符T()不存在时,编译器执行参数相关查找(ADL),这意味着它扫描两个参数的名称空间(即
istream
名称空间std
数据集的
名称空间)并在名称空间中找到合适的
运算符>>
,因此,如果不声明该转换运算符,它将起作用

这是一个很好的例子,说明了为什么允许隐式转换可能会有问题,并且应该避免——如果它是对类似于
操作符T()
的任何内容的隐式转换,则更是如此


一种解决方案是使转换运算符显式(仅限C++11),甚至更好的方法是使用命名转换函数。另一种方法是限制类型a
数据集可以转换为vía
std::enable_if
,或者如果只有少数目标类型,则通过显式编写每个非模板转换运算符。

这是什么
运算符T()
应该做什么呢?使其私有化可以防止从bool或ints(如数据集d=2)自动转换;或者如果(d){}.@iNFINITEi,
opator T()
数据集
转换为其他内容,而不是相反。e、 g.
数据集d;双x=d
或与此类似,在本例中,它为接受一个参数的任何函数启用
任何一元函数(d)
,而不管其类型如何-因为数据集可以转换为任何类型。
In file included from /usr/include/boost/type_traits/has_right_shift.hpp:43:0,
                 from /usr/include/boost/lexical_cast.hpp:171,
                 from /usr/include/boost/program_options/value_semantic.hpp:14,
                 from /usr/include/boost/program_options/options_description.hpp:13,
                 from /usr/include/boost/program_options.hpp:15,
                 ~/ProgramOptions.cpp:1:
/usr/include/boost/type_traits/detail/has_binary_operator.hpp: In instantiation of ‘const bool boost::detail::has_right_shift_impl::operator_exists<std::basic_istream<wchar_t>, Dataset>::value’:
/usr/include/boost/type_traits/detail/has_binary_operator.hpp:179:4:   instantiated from ‘const bool boost::detail::has_right_shift_impl::trait_impl1<std::basic_istream<wchar_t>, Dataset, boost::detail::has_right_shift_impl::dont_care, false>::value’
/usr/include/boost/type_traits/detail/has_binary_operator.hpp:214:4:   instantiated from ‘const bool boost::detail::has_right_shift_impl::trait_impl<std::basic_istream<wchar_t>, Dataset, boost::detail::has_right_shift_impl::dont_care>::value’
/usr/include/boost/type_traits/detail/has_binary_operator.hpp:221:1:   instantiated from ‘boost::has_right_shift<std::basic_istream<wchar_t>, Dataset, boost::detail::has_right_shift_impl::dont_care>’
/usr/include/boost/lexical_cast.hpp:394:1:   instantiated from ‘boost::detail::deduce_target_char_impl<boost::detail::deduce_character_type_later<Dataset> >’
/usr/include/boost/lexical_cast.hpp:420:89:   instantiated from ‘boost::detail::deduce_target_char<Dataset>’
/usr/include/boost/lexical_cast.hpp:679:92:   instantiated from ‘boost::detail::lexical_cast_stream_traits<std::basic_string<char>, Dataset>’
/usr/include/boost/lexical_cast.hpp:2339:19:   instantiated from ‘static Target boost::detail::lexical_cast_do_cast<Target, Source>::lexical_cast_impl(const Source&) [with Target = Dataset, Source = std::basic_string<char>]’
/usr/include/boost/lexical_cast.hpp:2519:50:   instantiated from ‘Target boost::lexical_cast(const Source&) [with Target = Dataset, Source = std::basic_string<char>]’
/usr/include/boost/program_options/detail/value_semantic.hpp:89:13:   instantiated from ‘void boost::program_options::validate(boost::any&, const std::vector<std::basic_string<charT> >&, T*, long int) [with T = Dataset, charT = char]’
/usr/include/boost/program_options/detail/value_semantic.hpp:170:13:   instantiated from ‘void boost::program_options::typed_value<T, charT>::xparse(boost::any&, const std::vector<std::basic_string<charT> >&) const [with T = Dataset, charT = char]’
~/ProgramOptions.cpp:276:1:   instantiated from here
/usr/include/boost/type_traits/detail/has_binary_operator.hpp:158:4: error: ambiguous overload for ‘operator>>’ in ‘boost::detail::has_right_shift_impl::make [with T = std::basic_istream<wchar_t>]() >> boost::detail::has_right_shift_impl::make [with T = Dataset]()’
/usr/include/boost/type_traits/detail/has_binary_operator.hpp:158:4: note: candidates are:
/usr/include/c++/4.6/istream:122:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_istream<_CharT, _Traits>::__istream_type& (*)(std::basic_istream<_CharT, _Traits>::__istream_type&)) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<wchar_t>]
/usr/include/c++/4.6/istream:126:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_istream<_CharT, _Traits>::__ios_type& (*)(std::basic_istream<_CharT, _Traits>::__ios_type&)) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<wchar_t>, std::basic_istream<_CharT, _Traits>::__ios_type = std::basic_ios<wchar_t>]
/usr/include/c++/4.6/istream:133:7: note: std::basic_istream<_CharT, _Traits>::__istream_type& std::basic_istream<_CharT, _Traits>::operator>>(std::ios_base& (*)(std::ios_base&)) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>, std::basic_istream<_CharT, _Traits>::__istream_type = std::basic_istream<wchar_t>]
/usr/include/c++/4.6/istream:241:7: note: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_istream<_CharT, _Traits>::__streambuf_type*) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>, std::basic_istream<_CharT, _Traits>::__streambuf_type = std::basic_streambuf<wchar_t>]
/usr/include/boost/type_traits/detail/has_binary_operator.hpp:70:13: note: boost::detail::has_right_shift_impl::no_operator boost::detail::has_right_shift_impl::operator>>(const boost::detail::has_right_shift_impl::any&, const boost::detail::has_right_shift_impl::any&)
template<typename T>
operator T() const;
class Dataset {
public:
  enum Name {
    JAVA, SUMATRA, ASIA, AFRICA
  };

  Dataset(const Name& name = JAVA) : name_(name) {}
  Dataset(const Dataset& dataset) : name_(dataset.name_) {}

  Dataset& operator=(const Dataset& dataset) {name_ = dataset.name_;  return *this; }
  bool operator==(const Dataset& dataset) const { return name_ == dataset.name_; }
  bool operator!=(const Dataset& dataset) const { return name_ != dataset.name_; }

  Name name() const {return name_;}

  std::string asString() const;

private:
  Name name_;
};
Dataset d(1); // Should be error
Dataset d = Dataset::JAVA; // Should be fine
double val = d; // Should be error
if(d == Dataset::SUMATRA) {} // should be fine
if(d == 3) {} // Should be error