Можно ли продлить boost::lexical_cast
обрабатывать другие типы данных, без фактического изменения этих классов?
В моем случае я хочу расширить его, чтобы обрабатывать такие вещи, как cv::Point
а также cv::Point3
, взяв разделенный на строки список координат и загрузив их .. Так что возможность сделать что-то вроде:
cv::Point mypoint = boost::lexical_cast<cv::Point>("2,4");
cv::Point
класс уже имеет потоковые операторы, но не совместим с istream
а также wstream
так что не получается.
редактировать
Я спрашиваю об этом, потому что я работаю в рамках с шаблонной функцией get_parameter
который использует boost::lexical_cast
преобразовать строку (считанную из файла конфигурации) в желаемый тип данных. Это прекрасно работает для целых & плавает, но сейчас мне приходится вызывать его несколько раз, чтобы прочитать 2D или 3D точку (или, что еще хуже, массивы коэффициентов). Было бы неплохо иметь возможность изменить lexical_cast для обработки этих случаев.
Таким образом, это не относится к OpenCV, я просто выбрал его в качестве простейшего типа данных. Меня больше интересует общее решение.
Редактировать 2
Вот пример приложения, которое я пробовал:
#include <opencv2/opencv.hpp>
#include <boost/lexical_cast.hpp>
template <typename T>
std::istream& operator>>(std::istream& stream, cv::Point_<T> &p) {
// Eventually something will go here
// to put stream into p
}
int main(int argc, char **argv) {
cv::Point_<float> p = boost::lexical_cast<cv::Point_<float>>(std::string("1,2"));
std::cout << "p = " << p << std::endl;
return 0;
}
И это терпит неудачу с красивой ошибкой шаблона C ++, например, так:
In file included from /home/rhand/Development/mlx/ml_3rdparty/install/boost/include/boost/lexical_cast.hpp:41:0,
from /home/rhand/Development/experiments/lexical_Cast/test.cc:2:
/home/rhand/Development/mlx/ml_3rdparty/install/boost/include/boost/lexical_cast.hpp: In instantiation of ‘struct boost::detail::deduce_target_char_impl<boost::detail::deduce_character_type_later<cv::Point_<float> > >’:
/home/rhand/Development/mlx/ml_3rdparty/install/boost/include/boost/lexical_cast.hpp:415:89: required from ‘struct boost::detail::deduce_target_char<cv::Point_<float> >’
/home/rhand/Development/mlx/ml_3rdparty/install/boost/include/boost/lexical_cast.hpp:674:92: required from ‘struct boost::detail::lexical_cast_stream_traits<std::basic_string<char>, cv::Point_<float> >’
/home/rhand/Development/mlx/ml_3rdparty/install/boost/include/boost/lexical_cast.hpp:2363:19: required from ‘static Target boost::detail::lexical_cast_do_cast<Target, Source>::lexical_cast_impl(const Source&) [with Target = cv::Point_<float>; Source = std::basic_string<char>]’
/home/rhand/Development/mlx/ml_3rdparty/install/boost/include/boost/lexical_cast.hpp:2543:50: required from ‘Target boost::lexical_cast(const Source&) [with Target = cv::Point_<float>; Source = std::basic_string<char>]’
/home/rhand/Development/experiments/lexical_Cast/test.cc:11:82: required from here
/home/rhand/Development/mlx/ml_3rdparty/install/boost/include/boost/static_assert.hpp:31:45: error: static assertion failed: Target type is neither std::istream`able nor std::wistream`able
# define BOOST_STATIC_ASSERT_MSG( ... ) static_assert(__VA_ARGS__)
^
/home/rhand/Development/mlx/ml_3rdparty/install/boost/include/boost/lexical_cast.hpp:388:13: note: in expansion of macro ‘BOOST_STATIC_ASSERT_MSG’
BOOST_STATIC_ASSERT_MSG((result_t::value || boost::has_right_shift<std::basic_istream<wchar_t>, T >::value),
^
make[2]: *** [CMakeFiles/test.dir/test.cc.o] Error 1
make[1]: *** [CMakeFiles/test.dir/all] Error 2
make: *** [all] Error 2
Вы можете определить специализацию boost :: lexical_cast для типов, которые вы хотите конвертировать.
Пример игрушки:
typedef struct { int x; int y; } Point;
namespace boost {
template<>
std::string lexical_cast(const Point& arg) { return "2,3"; }
}
int main () {
std::cout << boost::lexical_cast<std::string>(Point ()) << std::endl;
}
печать 2,3
,
Переход от строки к точке требует немного больше работы, но вы можете увидеть, как это сделать.
Если память работает правильно, вы сможете определить свободную функцию (istream& operator>>(istream&, cv::Point&)
) тот lexical_cast
будет использовать до тех пор, пока он определен до вызова lexical_cast.
Изменить: см. Перегрузка оператора istream>> C ++ для примера
Изменить 2: Вот рабочий пример (VS2013, Boost 1,44 [да, мне нужно обновить!]). Не могли бы вы опубликовать минимальный пример, который не удается в вашем случае?
#include <iostream>
#include <boost/lexical_cast.hpp>
template <typename ElementType>
struct Point
{
Point() : x(0), y(0) {}
ElementType x, y;
};
template <typename ElementType>
std::istream& operator>>(std::istream& stream, Point<ElementType> &p)
{
stream >> p.x;
stream.get();
stream >> p.y;
return stream;
}
template <typename ElementType>
std::ostream& operator<<(std::ostream& stream, const Point<ElementType> &p)
{
stream << p.x << "," << p.y;
return stream;
}
int main(int argc, char **argv)
{
Point<int> p = boost::lexical_cast<Point<int>>("1,2");
std::cout << "p=[" << p << "]";
std::cin.get();
return 0;
}
Редактировать 3: сделал Point
класс шаблонный, так как это, кажется, ваш случай
Редактировать 4: с OpenCV 2.4.10, также работает на вышеупомянутой установке:
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <opencv2/opencv.hpp>
template <typename ElementType>
std::istream& operator>>(std::istream& stream, cv::Point_<ElementType> &p)
{
stream >> p.x;
stream.get();
stream >> p.y;
return stream;
}
int main(int argc, char **argv)
{
auto cv_p = boost::lexical_cast<cv::Point_<float>>(std::string("1,2"));
std::cout << "opencv p=" << cv_p << "";
std::cin.get();
return 0;
}