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.45
    

    bekomme 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.44
    

    aber 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!


  • Administrator

    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 Validators

    Damit 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)


Anmelden zum Antworten