Как Boost Program_Options может обрабатывать вектор массивов?
В моей программе мне нужно выполнить некоторые преобразования с помощью библиотеки Eigen. Поскольку я использую файл конфигурации для пользователя для настройки некоторых параметров, я ищу способ интегрировать преобразования в этот файл конфигурации. Я придумал следующий код:
#include <boost\program_options.hpp>
#include <boost\log\trivial.hpp>
#include <Eigen\Geometry>
namespace po = boost::program_options;
int main(int ac, char* av[])
{
std::vector<std::array<double, 16>> trans;
try {
po::options_description desc("Options");
desc.add_options()
("help,h", "Produce help message")
("config,c", po::value<std::string>(&configPath), "Path of the config file.")
("trans", po::value<std::vector<std::array<double, 16>>>(&trans)->multitoken(), "Vector of 4D Transformation Matrix. Syntax: {x_11, ..., x_14, x_21, ..., x_24, ..., x_44}")
;
po::variables_map vm;
po::store(po::parse_command_line(ac, av, desc), vm);
po::notify(vm);
if (vm.count("help")) {
BOOST_LOG_TRIVIAL(info) << desc;
return EXIT_SUCCESS;
}
std::ifstream configFile(configPath);
po::store(po::parse_config_file(configFile, desc), vm);
po::notify(vm);
}
catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "error: " << e.what();
return EXIT_FAILURE;
}
catch (...) {
BOOST_LOG_TRIVIAL(error) << "Exception of unknown type!";
return EXIT_FAILURE;
}
Eigen::Affine3d transAff(Eigen::Matrix4d(trans.data()).transpose());
// Do some stuff
}
Но, к сожалению, я работаю с ошибкой при создании моего решения. Ошибка происходит в строке add_options преобразования и говорит:
myDirectory\vcpkg\installed\x64-windows\include\boost\lexical_cast\detail\converter_lexical.hpp(243): error C2338: Target type is neither std::istream`able nor std::wistream`able
myDirectory\vcpkg\installed\x64-windows\include\boost\lexical_cast\detail\converter_lexical.hpp(270): note: see reference to class template instantiation 'boost::detail::deduce_target_char_impl<boost::detail::deduce_character_type_later<std::array<double,16>>>' being compiled
myDirectory\vcpkg\installed\x64-windows\include\boost\lexical_cast\detail\converter_lexical.hpp(407): note: see reference to class template instantiation 'boost::detail::deduce_target_char<Target>' being compiled
with
[
Target=std::array<double,16>
]
myDirectory\vcpkg\installed\x64-windows\include\boost\lexical_cast\detail\converter_lexical.hpp(464): note: see reference to class template instantiation 'boost::detail::lexical_cast_stream_traits<Source,Target>' being compiled
with
[
Source=src,
Target=std::array<double,16>
]
myDirectory\vcpkg\installed\x64-windows\include\boost\lexical_cast\try_lexical_convert.hpp(196): note: see reference to class template instantiation 'boost::detail::lexical_converter_impl<Target,src>' being compiled
with
[
Target=std::array<double,16>
]
myDirectory\vcpkg\installed\x64-windows\include\boost\lexical_cast.hpp(41): note: see reference to function template instantiation 'bool boost::conversion::detail::try_lexical_convert<Target,Source>(const Source &,Target &)' being compiled
with
[
Target=std::array<double,16>,
Source=std::basic_string<char,std::char_traits<char>,std::allocator<char>>
]
myDirectory\vcpkg\installed\x64-windows\include\boost\program_options\detail\value_semantic.hpp(92): note: see reference to function template instantiation 'Target boost::lexical_cast<T,std::basic_string<char,std::char_traits<char>,std::allocator<char>>>(const Source &)' being compiled
with
[
Target=std::array<double,16>,
T=std::array<double,16>,
Source=std::basic_string<char,std::char_traits<char>,std::allocator<char>>
]
myDirectory\vcpkg\installed\x64-windows\include\boost\program_options\detail\value_semantic.hpp(149): note: see reference to function template instantiation 'void boost::program_options::validate<T,char>(boost::any &,const std::vector<std::string,std::allocator<_Ty>> &,T *,long)' being compiled
with
[
T=std::array<double,16>,
_Ty=std::string
]
myDirectory\vcpkg\installed\x64-windows\include\boost\program_options\detail\value_semantic.hpp(184): note: see reference to function template instantiation 'void boost::program_options::validate<std::array<double,16>,char>(boost::any &,const std::vector<std::string,std::allocator<_Ty>> &,std::vector<std::array<double,16>,std::allocator<std::array<double,16>>> *,int)' being compiled
with
[
_Ty=std::string
]
myDirectory\vcpkg\installed\x64-windows\include\boost\program_options\detail\value_semantic.hpp(177): note: while compiling class template member function 'void boost::program_options::typed_value<std::vector<std::array<double,16>,std::allocator<_Ty>>,char>::xparse(boost::any &,const std::vector<std::string,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char>>>> &) const'
with
[
_Ty=std::array<double,16>
]
myDirectory\myProgram\src\myProgram.cpp(91): note: see reference to class template instantiation 'boost::program_options::typed_value<std::vector<std::array<double,16>,std::allocator<_Ty>>,char>' being compiled
with
[
_Ty=std::array<double,16>
]
Я думаю, что ошибка связана с тем, что векторы массивов не поддерживаются так, как я пытаюсь это сделать. Есть ли способ достичь этого или даже более разумный способ обработки этих преобразований?
Большое спасибо!
1 ответ
Мне удалось решить вопрос самостоятельно, с некоторыми изменениями. Если у кого-то есть такая же проблема, я надеюсь, что смогу помочь ему с этим ответом.
Массивы в C++
На первом этапе я изменил все свои массивы на std::vector
из-за большей функциональности и из-за того, что во многих сообщениях не рекомендуется использовать массивы, как, например, здесь.
С помощью std::string
как временная замена для внутреннего std::vector
Поскольку вектор в векторе - сложная задача для параметров программы (так как мультитокен просто добавляет элементы в вектор и не может различаться между слоями векторов), я заменил внутренний std::vector
со строкой, поэтому add_options теперь
std::vector<std::string> trans;
try {
po::options_description desc("Options");
desc.add_options()
("help,h", "Produce help message")
("config,c", po::value<std::string>(&configPath), "Path of the config file.")
("trans", po::value<std::vector<std::string>>(&trans)->multitoken(), "Vector of 4D Transformation Matrix. Syntax: x_11 ... x_14 x_21 ... x_24 ... x_44")
;
...
Преобразование из std::string
в std::vector<double>
Теперь мы можем преобразовать строки из входных данных в векторы двойников, так как они могут быть использованы для создания Eigen::Matrix
а также Eigen::Vector
, Я получил идею от NathanOliver в этом посте, который я использую так:
std::vector<double> str2vec(std::string str) {
std::vector<double> out;
std::stringstream ss(str);
double tmpVal;
while (ss >> tmpVal)
out.push_back(tmpVal);
return out;
}
Все вместе
В конце мой код выглядит так:
#include <boost\program_options.hpp>
#include <boost\log\trivial.hpp>
#include <Eigen\Geometry>
namespace po = boost::program_options;
std::vector<double> str2vec(std::string str) {
std::vector<double> out;
std::stringstream ss(str);
double tmpVal;
while (ss >> tmpVal)
out.push_back(tmpVal);
return out;
}
int main(int ac, char* av[])
{
std::vector<std::string> transVecStr;
try {
po::options_description desc("Options");
desc.add_options()
("help,h", "Produce help message")
("config,c", po::value<std::string>(&configPath), "Path of the config file.")
("transVecStr", po::value<std::vector<std::string>>(&transVecStr)->multitoken(), "Vector of 4D Transformation Matrix. Syntax: x_11 ... x_14 x_21 ... x_24 ... x_44")
;
po::variables_map vm;
po::store(po::parse_command_line(ac, av, desc), vm);
po::notify(vm);
if (vm.count("help")) {
BOOST_LOG_TRIVIAL(info) << desc;
return EXIT_SUCCESS;
}
std::ifstream configFile(configPath);
po::store(po::parse_config_file(configFile, desc), vm);
po::notify(vm);
}
catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "error: " << e.what();
return EXIT_FAILURE;
}
catch (...) {
BOOST_LOG_TRIVIAL(error) << "Exception of unknown type!";
return EXIT_FAILURE;
}
std::vector<Eigen::Affine3d> affineVec;
for(int i = 0; i<transVecStr.size();i++){
affineVec.emplace_back(Eigen::Matrix4d(str2vec(transVecStr[i]).data()).transpose());
}
// Do some stuff
}