Frage zu config-file syntax in boost::program_options
-
Hi,
hab vor kurzem begonnen, mit boost::program_options zu experimentieren, da ich es in meinem Projekt einsetzen möchte -- allerdings war es mir bis jetzt noch nicht möglich, herauszufinden, wie ich eine Abfolge von floating-point Werten im config-File spezifizieren kann (die "Doku" ist ja leider auch nicht sehr umfangreich). Der Code sieht folgendemaßen aus, großteils zusammengeflickt aus den Samles:
options_description gui("GUI options"); gui.add_options() ("gui.dummy-float", value<vector<float> >()->multitoken(), "some dummy double value") ; // ... options_description visible("Visible options"); visible.add(general).add(gui); options_description config_file_options("Config file options"); config_file_options.add(gui).add(backend); positional_options_description p; p.add("input-file", -1); variables_map vm; store(command_line_parser(ac, av). options(visible).positional(p).run(), vm); ifstream ifs("testConfig.cfg"); if( !ifs ) throw std::runtime_error( "config file not found" ); store(parse_config_file(ifs, config_file_options), vm); notify(vm); // ... if( vm.count("gui.dummy-float")) { vector<float> dv = vm["gui.dummy-float"].as<vector<float> >(); for( vector<float>::iterator it = dv.begin(); it != dv.end(); ++it ) cout << "dummy-float: " << *it << std::endl; }Wenn ich nun als Parameter zB. "--gui.dummy-float=3.354 12.45" verwende, wird das korrekt als Zahlenarray erkannt und geparst. Wenn ich jedoch im Config-file sowas hier schreibe
[gui] dummy-float=3.354 12.45bekomme ich eine Exception geworfen: "in option 'gui.dummy-float': invalid option value '3.354 12.45'". Ich hab herausgefunden, dass sowas hier funktionieren würde:
[gui] dummy-float=3.333 dummy-float=4.44aber das wird spätestens bei 4x4-Matrizen etwas mühsam und unlesbar.
Hat jemand eine einigermaßen vernünftige Lösung dafür? Und warum diese Inkonsistenz zwischen Programmparametern und Config-Files?
Danke schon mal!
-
iko79 schrieb:
Hat jemand eine einigermaßen vernünftige Lösung dafür?
Auf die Schnelle käme mir aktuell nur sowas in den Sinn:
Custom ValidatorsDamit kannst du ein eigenes Format verwenden, welches du dann selber parst.
iko79 schrieb:
Und warum diese Inkonsistenz zwischen Programmparametern und Config-Files?
Genau kann ich dir das nicht sagen. Ich weiss nur, dass dies eine zum Teil gängige Art ist, um mehrfache Werte einem Name in einem INI File zuzuordnen.
Grüssli
-
Hallo,
ich verwende jetzt Custom Validators, danke für den Vorschlag.
Allerdings habe ich ein Problem damit: Wenn ich eine Klasse definiere...
class Vec3f { //... }; typedef Vec3f Vec3;...per Überladung eine validierungs-Funktion zur verfügung stelle...
void validate( any &v, const std::vector<std::string> &values, Vec3*, int )...und eine option mit ensprechendem Typ zu meiner option_description hinzufüge...
options_description projector( "Projector options" ); projector.add_options() ( "position, value<Vec3>(), "bla" );...dann funktioniert das auch.
Allerdings, sobald ich die Klasse Vec3 in einen namespace verpacke...
namespace osg { class Vec3f { //... }; typedef Vec3f Vec3; };...und die überladene validierungs-Funktion...
void validate( any &v, const std::vector<std::string> &values, osg::Vec3*, int )...als auch die Option entsprechend ändere...
options_description projector( "Projector options" ); projector.add_options() ( "position", value<osg::Vec3>(), "bla" );...wird mein überladener Validator nicht mehr gefunden. Statt dessen wird der default Validator (die Template-Funktion in value_semantic.hpp) verwendet, die versucht, den Vec3-Eintrag per lexical_cast zu konvertieren. Nachdem aber in osg::Vec3 keine << oder >> Operatoren für std::basic_istream vorhanden sind führt das natürlich zu folgendem Fehler (boost 1.38.0, MSVC 9.0):
MSVC 9.0 schrieb:
h:\ahumari\svn\libs\boost-1.38.0\boost\lexical_cast.hpp(771) : error C2679: binary '>>' : no operator found which takes a right-hand operand of type 'osg::Vec3' (or there is no acceptable conversion)
> j:\program files\microsoft visual studio 9.0\vc\include\istream(1144): could be 'std::basic_istream<_Elem,_Traits> &std::operator >><std::char_traits<char>>(std::basic_istream<_Elem,_Traits> &,signed char *)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(1146): or 'std::basic_istream<_Elem,_Traits> &std::operator >><std::char_traits<char>>(std::basic_istream<_Elem,_Traits> &,signed char &)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(1148): or 'std::basic_istream<_Elem,_Traits> &std::operator >><std::char_traits<char>>(std::basic_istream<_Elem,_Traits> &,unsigned char *)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(1150): or 'std::basic_istream<_Elem,_Traits> &std::operator >><std::char_traits<char>>(std::basic_istream<_Elem,_Traits> &,unsigned char &)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(155): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(std::basic_istream<_Elem,_Traits> &(__cdecl *)(std::basic_istream<_Elem,_Traits> &))'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(161): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(std::basic_ios<_Elem,_Traits> &(__cdecl *)(std::basic_ios<_Elem,_Traits> &))'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(168): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(std::ios_base &(__cdecl *)(std::ios_base &))'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(175): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(std::_Bool &)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(194): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(short &)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(228): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(unsigned short &)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(247): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(int &)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(273): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(unsigned int &)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(291): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(long &)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(309): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(__w64 unsigned long &)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(329): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(__int64 &)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(348): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(unsigned __int64 &)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(367): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(float &)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(386): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(double &)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(404): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(long double &)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(422): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(void *&)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> j:\program files\microsoft visual studio 9.0\vc\include\istream(441): or 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::operator >>(std::basic_streambuf<_Elem,_Traits> *)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> while trying to match the argument list '(std::basic_istream<_Elem,_Traits>, osg::Vec3)'
> with
> [
> _Elem=char,
> _Traits=std::char_traits<char>
> ]
> h:\ahumari\svn\libs\boost-1.38.0\boost\lexical_cast.hpp(1151) : see reference to function template instantiation 'bool boost::detail::lexical_stream_limited_src<CharT,Base,Traits>::operator >><Target>(InputStreamable &)' being compiled
> with
> [
> CharT=char_type,
> Base=base,
> Traits=traits,
> Target=osg::Vec3,
> InputStreamable=osg::Vec3
> ]
> h:\ahumari\svn\libs\boost-1.38.0\boost\lexical_cast.hpp(1177) : see reference to function template instantiation 'Target boost::detail::lexical_cast<Target,src,false,char_type>(const std::basic_string<_Elem,_Traits,_Ax> &,CharT *,size_t)' being compiled
> with
> [
> Target=osg::Vec3,
> _Elem=char,
> _Traits=std::char_traits<char>,
> _Ax=std::allocator<char>,
> CharT=char_type
> ]
> h:\ahumari\svn\libs\boost-1.38.0\boost\program_options\detail\value_semantic.hpp(89) : see reference to function template instantiation 'Target boost::lexical_cast<T,std::basic_string<_Elem,_Traits,_Ax>>(const Source &)' being compiled
> with
> [
> Target=osg::Vec3,
> T=osg::Vec3,
> _Elem=char,
> _Traits=std::char_traits<char>,
> _Ax=std::allocator<char>,
> Source=std::basic_string<char,std::char_traits<char>,std::allocator<char>>
> ]
> h:\ahumari\svn\libs\boost-1.38.0\boost\program_options\detail\value_semantic.hpp(170) : see reference to function template instantiation 'void boost::program_options::validate<T,char>(boost::any &,const std::vector<_Ty> &,T *,long)' being compiled
> with
> [
> T=osg::Vec3,
> _Ty=std::string
> ]
> h:\ahumari\svn\libs\boost-1.38.0\boost\program_options\detail\value_semantic.hpp(163) : while compiling class template member function 'void boost::program_options::typed_value<T,charT>::xparse(boost::any &,const std::vector<_Ty> &) const'
> with
> [
> T=osg::Vec3,
> charT=char,
> _Ty=std::string
> ]
> h:\iko\vader\source\main.cpp(375) : see reference to class template instantiation 'boost::program_options::typed_value<T,charT>' being compiled
> with
> [
> T=osg::Vec3,
> charT=char
> ]Kann mir dabei jemand helfen? Warum wird meine Funktion nicht erkannt?
Danke,
iko.
-
Okay, ich hab inzwischen rausgefunden, dass es daran liegt, dass die überladenen validate-Funktionen im globalen Namespace liegen. Bringe ich sie im selben Namespace wie die genannte Template-Funktion unter (boost::program_options), dann geht's.
Allerdings ist mir der Grund dafür schleierhaft. Im globalen Namespace sollte osg::Vec3 doch die selbe Bedeutung haben wie in boost::program_options? Hat jemand eine Erklärung dafür? (Compiler-Bug? O_o)