2014-11-21 4 views
2

Предположим, что мне нужна специальная обработка для целочисленных опций. Согласно документации, я должен написать свою собственную функцию проверки. Рассмотрим следующую короткую программу.Пользовательский валидатор для boost program_options не работает с GCC, работает с MSVC

#include <iostream> 
#include <vector> 
#include <string> 

#include <boost/program_options.hpp> 

namespace po = boost::program_options; 

namespace boost { namespace program_options { 
template <class charT> 
void validate(boost::any& v, const std::vector<std::basic_string<charT> >& xs, unsigned int*, int) 
{ 
    std::cout << "validate is redefined" << std::endl; 
    // do something else 
} 
}} 

int main(int argc, char* argv[]) 
{ 
    po::options_description cmdLineOptions; 
    po::variables_map vm; 

    unsigned int v; 
    const char* args[] = {"tst", "-k", "10"}; 

    cmdLineOptions.add_options() 
     ("key,k", po::value<unsigned int>(&v)->required()) 
     ; 

    po::store(po::command_line_parser(sizeof(args)/sizeof(args[0]), args).options(cmdLineOptions).run(), vm); 
    po::notify(vm); 

    std::cout << v << '\n'; 

    return 0; 
} 

Он отлично работает в VS 2013 и выходы

validate is redefined 
10 

В НКУ он никогда не шаги внутри функции валидации.

Доказательство: http://coliru.stacked-crooked.com/a/fd558ebf987a4bbe

Если я пытаюсь использовать пользовательский тип вместо неподписанных Int, GCC будет пытаться использовать Validate от program_option в любом случае и в конечном итоге с кучей ошибок.

Что я делаю неправильно?

ответ

1

В предварительной догадке, рассмотреть вопрос об использовании

BOOST_STRONG_TYPEDEF(unsigned int, Unsigned); 

Похоже, что это плохая идея, чтобы настроить поведение только на встроенных типах.


Решение: Это связано с частичным заказом.

Если вы переместите свою перегрузку за пределы пространства имен boost::program_options, она начнет работать (поскольку она больше не конкурирует с базовым шаблоном).

Live On Coliru

#include <iostream> 
#include <vector> 
#include <string> 

#include <boost/any.hpp> 
#include <boost/serialization/strong_typedef.hpp> 
#include <boost/program_options.hpp> 

BOOST_STRONG_TYPEDEF(unsigned, Unsigned) 

template<class charT> 
    void validate(boost::any& v, 
      const std::vector< std::basic_string<charT> >& xs, 
      Unsigned* p, int) 
    { 
     std::cout << "validate is redefined" << std::endl; 
     // do something else 
    } 

namespace po = boost::program_options; 

int main() 
{ 
    po::options_description cmdLineOptions; 
    po::variables_map vm; 

    Unsigned v; 
    const char* args[] = {"tst", "-k", "10"}; 

    cmdLineOptions.add_options() 
     ("key,k", po::value<Unsigned>(&v)->required()) 
     ; 

    po::store(po::command_line_parser(sizeof(args)/sizeof(args[0]), args).options(cmdLineOptions).run(), vm); 
    po::notify(vm); 

    std::cout << v << '\n'; 

    return 0; 
} 

Причина, скорее всего, как известно сломаны 2-фазы поиска MSVC в

+0

че anks для обходного пути. Да, похоже, что частичное упорядочение GCC нарушено. – noxmetus

+0

@noxmetus Я еще не уверен. Кланг делает то же самое. Вероятно, это может быть документировано немного лучше ... – sehe

+0

Обходной путь не очень полезен, поскольку обычно нужно вызвать check_first_occurrence и get_single_string внутри валидатора, и они определены внутри файлов заголовков program_options. – noxmetus