I'm trying to extend lexical_cast to handle string->cv::Point conversions, with code like so:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
namespace boost {
template<>
cv::Point2f lexical_cast(const std::string &str) {
std::vector<std::string> parts;
boost::split(parts, str, boost::is_any_of(","));
cv::Point2f R;
R.x = boost::lexical_cast<float>(parts[0]);
R.y = boost::lexical_cast<float>(parts[1]);
return R;
}
}
int main(int argc, char **argv) {
auto p = boost::lexical_cast<cv::Point2f>(std::string("1,2"));
std::cout << "p = " << p << std::endl;
return 0;
}
And it works great.. However, cv::Point2f is actually cv::Point_<T> where T can be int, float, double, etc. I can't find anyway to expose that templated arg to the lexical_cast, so that I can have a single lexical_cast function that can handle all cv::Point_<T> types.
template <typename T>
struct point_type {};
template <typename T>
struct point_type<cv::Point_<T>> { using type = T; };
namespace boost {
template <typename T, typename U = typename point_type<T>::type>
T lexical_cast(const std::string &str)
{
std::vector<std::string> parts;
boost::split(parts, str, boost::is_any_of(","));
T R;
R.x = boost::lexical_cast<U>(parts[0]);
R.y = boost::lexical_cast<U>(parts[1]);
return R;
}
}
DEMO
The previous, a little more complicated solution, if you don't like this implicit second template parameter of lexical_cast:
#include <type_traits>
template <typename T>
struct is_point : std::false_type {};
template <typename T>
struct is_point<cv::Point_<T>> : std::true_type {};
template <typename T>
struct point_type;
template <typename T>
struct point_type<cv::Point_<T>> { using type = T; };
namespace boost {
template <typename T>
auto lexical_cast(const std::string &str)
-> typename std::enable_if<is_point<T>::value, T>::type
{
std::vector<std::string> parts;
boost::split(parts, str, boost::is_any_of(","));
using U = typename point_type<T>::type;
T R;
R.x = boost::lexical_cast<U>(parts[0]);
R.y = boost::lexical_cast<U>(parts[1]);
return R;
}
}
DEMO 2
Related
I have the following, it accepts a function pointer type, and returns the typeid of each argument in a vector.
template <typename Ret, typename... Types>
auto ArgTypes(Ret(*pFn)(Types...))
{
std::vector<std::type_index> vec;
vec.insert(vec.end(), {typeid(Types)...});
return vec;
}
I invoke it like this:
typedef int (*tExampleFn) (int a,bool b,char* c,long long d);
tExampleFn fakePtr = (tExampleFn)0;
auto argTypes = ArgTypes(&fakePtr);
As you can see, I have to make this fake function pointer for the template to work. I would instead like it to work like this:
template <typename Ret, typename... Types> // guide Ret and Types into shape Ret(*pFn)(Types...) somehow
auto ArgTypes()
{
std::vector<std::type_index> vec;
vec.insert(vec.end(), {typeid(Types)...});
return vec;
}
typedef int (*tExampleFn) (int a,bool b,char* c,long long d);
auto argTypes = ArgTypes<tExampleFn>();
I cannot get the template to work this way. The first template arg Ret gets assinged the full type of the typedef tExampleFn. How can I guide the template to use the shape Ret(*pFn)(Types...), but without having to pass an intermediate function pointer.
As mentioned by NathanOliver you can call the first version via ArgTypes(tExampleFn{}).
To avoid creating an instance of the function pointer type altogether you can use partial template specialization. This doesn't work for function templates though.
#include <vector>
#include <typeindex>
#include <tuple>
template <typename Ret, typename... Types>
auto ArgTypes(Ret(*pFn)(Types...))
{
std::vector<std::type_index> vec;
vec.insert(vec.end(), {typeid(Types)...});
return vec;
}
template <typename T>
struct arg_types;
template <typename Ret,typename ... Types>
struct arg_types<Ret(*)(Types...)> {
auto operator()() {
std::vector<std::type_index> vec;
vec.insert(vec.end(), {typeid(Types)...});
return vec;
}
};
int main()
{
typedef int (*tExampleFn) (int a,bool b,char* c,long long d);
ArgTypes(tExampleFn{});
arg_types<tExampleFn>{}();
}
Thanks everyone, I've combined the answers and comments with some external help into the following:
#include <iostream>
#include <typeinfo>
#include <typeindex>
#include <span>
typedef int (*tExampleFn) (int a,bool b,char* c,long long d);
template<typename T>
struct arg_types {};
template<typename R, typename... A>
struct arg_types<R(*)(A...)> {
inline static const std::type_index value[] = {typeid(A)...};
};
template<typename T>
static constexpr std::span<const std::type_index> arg_types_v = arg_types<T>::value;
int main()
{
auto vec = arg_types_v<tExampleFn>;
for (const auto& t : vec)
{
std::cout << t.hash_code() << std::endl;
}
}
What I'm trying to do is have two function templates: one that translates a string to an boost::optional<some integer type> and one that translates a string to a boost::optional<some enum type>. Something like this:
template<typename T> boost::optional<T> func(const std::string &s) { return boost::make_optional(std::stoi(s));}
template<typename T> boost::optional<T> func(const std::string &s) { return boost::make_optional(EnumMapper<T>::map_string_to_enum<T>(s));}
enum Color { Red, Blue, Green};
enum Direction { Up, Down, Left, Right};
auto a = func<int>("1234");
auto b = func<Color>("red");
auto c = func<Direction>("up");
I have something working where I make specializations for every enum type:
template<> boost::optional<Color> func(const std::string &s) { return boost::make_optional(EnumMapper<Color>::map_string_to_enum<Color>(s));}
template<> boost::optional<Direction> func(const std::string &s) { return boost::make_optional(EnumMapper<Direction>::map_string_to_enum<Direction>(s));}
but with literally dozens of enums this seems ugly and error prone. I have a feeling that this is what type traits are there for, but none of the examples I found seems to work for what I want to do.
Edit: Thanks to songyuanyao! This works:
#include <iostream>
#include <type_traits>
#include <string>
#include <boost/optional.hpp>
#include <cstdint>
enum Color {
Red,
Green,
Blue
};
enum Direction {
Up,
Down,
Left,
Right
};
template <typename T> struct EnumMapper { static boost::optional<T> map_string_to_enum(const std::string &s) = delete; };
template <> boost::optional<Color> EnumMapper<Color>::map_string_to_enum(const std::string &s) {
return Color::Green;
}
template <> boost::optional<Direction> EnumMapper<Direction>::map_string_to_enum(const std::string &s) {
return Direction::Right;
}
template<typename T>
typename std::enable_if<std::is_enum<T>::value, boost::optional<T>>::type
func(const std::string &s) {
return EnumMapper<T>::map_string_to_enum(s);
}
template<typename T>
typename std::enable_if<std::is_integral<T>::value, boost::optional<T>>::type
func(const std::string &s) {
return boost::make_optional<T>(std::stoi(s));
}
int
main() {
auto a = func<std::uint8_t>("123");
std::cout << static_cast<int>(*a) << std::endl;
auto b = func<Color>("Red");
std::cout << static_cast<int>(*b) << std::endl;
auto c = func<Direction>("Up");
std::cout << static_cast<int>(*c) << std::endl;
auto d = func<std::uint32_t>("2345");
std::cout << static_cast<int>(*d) << std::endl;
}
You can use the type trait std::is_enum, and apply SFINAE.
template<typename T>
typename std::enable_if<std::is_enum<T>::value, boost::optional<T>>::type
func(const std::string &s) {
return boost::make_optional(EnumMapper<T>::map_string_to_enum<T>(s));
}
Note that you have to constrain on type for the 1st overload too. You can check whether it's int, or use std::is_integral. E.g.
template<typename T>
typename std::enable_if<std::is_same<T, int>::value, boost::optional<T>>::type
func(const std::string &s) {
return boost::make_optional(std::stoi(s));
}
I was wondering if there was a way to loop through the dimensions of a boost point model. I am trying to create a function to do calculations on two custom points, with a definable number of dimensions. In other words the number of dimensions of each point will match, however they will not be a constant value. I want to do the same operations on each dimension, so I need to do a loop in order to achieve this.
An example of what I want I want to do would be:
for(std::size_t dim = 0; dim < D; dim++){
CoordinateType d = get<dim>();
//do stuff to d
set<dim>(d);
}
I know this would not work because d is not a compile-time constant.
Thanks!
As an alternative approach I thought you should be able to adapt the Boost Geometry point model as a Fusion sequence.
Live On Coliru
#include <iostream>
namespace bg = boost::geometry;
namespace fus = boost::fusion;
int main() {
bg::model::point<double, 7, bg::cs::cartesian> p1;
// set some nice values
p1.set<0>(7); p1.set<1>(14); p1.set<2>(21); p1.set<3>(28);
p1.set<4>(35); p1.set<5>(42); p1.set<6>(49);
fus::for_each(fus::as_vector(p1), [](double x) { std::cout << x << ' '; });
}
Prints
7 14 21 28 35 42 49
This is pretty versatile (and will give you many more algorithms than just for_each). In the sample I've not gone all the way so you can actually say for_each(p1, f) instead of for_each(as_vector(p1), f) but you know... the proverbial exercise for the reader.
There's a bit of extension "glue" code involved here. I simply followed the documentation here
See the full listing here:
Live On Coliru
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/include/as_vector.hpp>
namespace bg_to_fusion {
using namespace boost;
struct bg_point_tag;
struct example_struct_iterator_tag;
template<typename Point, int Pos>
struct point_iterator
: fusion::iterator_base<point_iterator<Point, Pos> >
{
BOOST_STATIC_ASSERT(Pos >=0 && Pos <geometry::traits::dimension<typename remove_cv<Point>::type>::value);
typedef Point point_type;
typedef mpl::int_<Pos> index;
//typedef fusion::random_access_traversal_tag category;
typedef fusion::forward_traversal_tag category;
point_iterator(Point& p) : point_(p) {}
Point& point_;
};
}
namespace boost { namespace fusion {
// tag dispatch
namespace traits {
template <typename T, size_t dims, typename cs>
struct tag_of<geometry::model::point<T, dims, cs> > {
typedef bg_to_fusion::bg_point_tag type;
};
template <typename Point, int Pos>
struct tag_of<bg_to_fusion::point_iterator<Point, Pos> > {
typedef bg_to_fusion::example_struct_iterator_tag type;
};
}
namespace extension {
//////////////////////////////////////////////////////
// Point extension implementations
template<>
struct is_sequence_impl<bg_to_fusion::bg_point_tag>
{
template<typename T>
struct apply : mpl::true_ {};
};
template <>
struct size_impl<bg_to_fusion::bg_point_tag> {
template <typename Point>
struct apply : mpl::integral_c<size_t, geometry::traits::dimension<typename remove_cv<Point>::type>::value> { };
};
// begin
template<>
struct begin_impl<bg_to_fusion::bg_point_tag>
{
template<typename Point>
struct apply
{
typedef typename bg_to_fusion::point_iterator<Point, 0> type;
static type
call(Point& p)
{
return type(p);
}
};
};
// end
template<>
struct end_impl<bg_to_fusion::bg_point_tag>
{
template<typename Point> struct apply {
typedef typename bg_to_fusion::point_iterator<Point, geometry::traits::dimension<Point>::value> type;
static type call(Point& p) {
return type(p);
}
};
};
////////////////////////
// Iterator extension implementations
// value_of
template <>
struct value_of_impl<bg_to_fusion::example_struct_iterator_tag> {
template<typename Iterator> struct apply;
template<typename Point, int Pos>
struct apply<bg_to_fusion::point_iterator<Point, Pos> > {
typedef typename geometry::traits::coordinate_type<typename remove_cv<Point>::type>::type type;
};
};
// deref
template<>
struct deref_impl<bg_to_fusion::example_struct_iterator_tag>
{
template<typename Iterator>
struct apply;
template<typename Point, int Pos>
struct apply<bg_to_fusion::point_iterator<Point, Pos> >
{
typedef typename geometry::traits::coordinate_type<typename remove_cv<Point>::type>::type coordinate_type;
//typedef typename mpl::if_<is_const<Point>, coordinate_type const&, coordinate_type&>::type type;
typedef coordinate_type type;
static type
call(bg_to_fusion::point_iterator<Point, Pos> const& it) {
return it.point_.template get<Pos>();
}
};
};
// next
template<>
struct next_impl<bg_to_fusion::example_struct_iterator_tag> {
template<typename Iterator> struct apply
{
typedef typename Iterator::point_type point_type;
typedef typename Iterator::index index;
typedef typename bg_to_fusion::point_iterator<point_type, index::value + 1> type;
static type
call(Iterator const& i) {
return type(i.point_);
}
};
};
}
} }
I am not very familiar with boost geometry but it seems you have to iterate through the coordinates at compile time. The way to do this is by creating a recursion. The class apply below will perform such recursion and call a functor on each coordinate of the point.
All you have to do is to write your own functor and overload its operator() in case you want to specialise behaviour for certain coordinates. The functor in the example below simply prints the coordinates and is specialised when reading the 3rd coordinate.
#include <boost/geometry.hpp>
#include <iostream>
#include <type_traits>
namespace bg = boost::geometry;
template <int I>
using int_ = std::integral_constant<int, I>;
//recursive call that iterates the point and calls F on its coordinate
template <class Point, class F, std::size_t I = 0>
struct apply {
static void call(Point& point, F& f) {
f(point, int_<I>());
apply<Point, F, I+1>::call(point, f);
}
};
//specialisation to end the recursion
template <class CT, std::size_t DIM, class S, template <class, std::size_t, class> class Point, class F>
struct apply<Point<CT, DIM, S>, F, DIM> {
static void call(Point<CT, DIM, S>& point, F& f){}
};
//interface for calling the function
template <class Point, class F>
void apply_functor(Point& point, F& f) {
apply<Point, F>::call(point, f);
}
//example functor
template <class Point>
struct functor {
template <class Index>
void operator()(Point& point, Index I) {
std::cout << "I am coordinate " << Index::value << " and my value is " << bg::get<Index::value>(point) << std::endl;
}
// used for overloading when reading the 3rd coordinate
void operator()(Point& point, int_<2>) {
std::cout << "I am coordinate " << 2 << " and I am specialised with value " << bg::get<2>(point) << std::endl;
}
};
//3-dimensional point type
using point_type = bg::model::point<double, 3, bg::cs::cartesian>;
int main(int argc, char** argv) {
point_type point(1,2,3);
functor<point_type> f;
apply_functor(point, f);
return 0;
}
I am trying to use boost fusion for one of my projects and I an figuring out how to get type names and variable names for structures and classes.
#include <typeinfo>
#include <string>
#include <iostream>
#include <boost/fusion/include/sequence.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/adapt_adt.hpp>
#include <boost/lexical_cast.hpp>
using namespace boost::fusion;
struct Foo
{
int integer_value;
bool boolean_value;
};
class Bar
{
int integer_value;
bool boolean_value;
public:
Bar(int i_val, bool b_val):integer_value(i_val),boolean_value(b_val) {}
int get_integer_value() const { return integer_value; }
void set_integer_value(int i_val) { integer_value = i_val; }
bool get_boolean_value() const { return boolean_value; }
void set_boolean_value(bool b_val) { boolean_value = b_val; }
};
BOOST_FUSION_ADAPT_STRUCT(
Foo,
(int, integer_value)
(bool, boolean_value)
)
BOOST_FUSION_ADAPT_ADT(
Bar,
(int, int, obj.get_integer_value() , obj.set_integer_value(val))
(bool, bool, obj.get_boolean_value(), obj.set_boolean_value(val))
)
struct DisplayMembers
{
template <typename T>
void operator()(T& t) const {
std::cout << typeid(t).name() << " : " << boost::lexical_cast<std::string>(t) << std::endl;
}
};
int main(int argc, char *argv[])
{
struct Foo f = { 33, false};
for_each(f, DisplayMembers());
Bar b(34,true);
for_each(b, DisplayMembers());
return 0;
}
In the above example the result is
int : 33
bool : 0
struct boost::fusion::extension::adt_attribute_proxy<class Bar,0,0> : 34
struct boost::fusion::extension::adt_attribute_proxy<class Bar,1,0> : 1
I want the result as
int : integer_value : 33
bool : boolean_value : 0
int : integer_value : 34
bool : boolean_value : 1
I distilled the answer by sehe into something much simpler, provided you are using C++14
#include <iostream>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/mpl/range_c.hpp>
struct MyStruct {
std::string foo;
double bar;
};
BOOST_FUSION_ADAPT_STRUCT(MyStruct,
foo,
bar)
namespace fuz = boost::fusion;
namespace mpl = boost::mpl;
int main(int argc, char* argv[]) {
MyStruct dummy{"yo",3.14};
fuz::for_each(mpl::range_c<
unsigned, 0, fuz::result_of::size<MyStruct>::value>(),
[&](auto index){
std::cout << "Name: "
<< fuz::extension::struct_member_name<MyStruct,index>::call()
<< " Value: "
<< fuz::at_c<index>(dummy) << std::endl;
});
}
Outputs:
Name: foo Value: yo
Name: bar Value: 3.14
See it live on coliru
There's boost::fusion::extension::struct_member_name<S, N::value> to access the names.
Here's a generic fusion object visitor that I use:
namespace visitor {
template <typename Flavour, typename T> struct VisitorApplication;
namespace detail
{
template <typename V, typename Enable = void>
struct is_vector : boost::mpl::false_ { };
template <typename T>
struct is_vector<std::vector<T>, void> : boost::mpl::true_ { };
namespace iteration
{
// Iteration over a sequence
template <typename FusionVisitorConcept, typename S, typename N>
struct members_impl
{
// Type of the current member
typedef typename boost::fusion::result_of::value_at<S, N>::type current_t;
typedef typename boost::mpl::next<N>::type next_t;
typedef boost::fusion::extension::struct_member_name<S, N::value> name_t;
static inline void handle(FusionVisitorConcept& visitor, const S& s)
{
visitor.start_member(name_t::call());
VisitorApplication<FusionVisitorConcept, current_t>::handle(visitor, boost::fusion::at<N>(s));
visitor.finish_member(name_t::call());
members_impl<FusionVisitorConcept, S, next_t>::handle(visitor, s);
}
};
// End condition of sequence iteration
template <typename FusionVisitorConcept, typename S>
struct members_impl<FusionVisitorConcept, S, typename boost::fusion::result_of::size<S>::type>
{
static inline void handle(FusionVisitorConcept const&, const S&) { /*Nothing to do*/ }
};
// Iterate over struct/sequence. Base template
template <typename FusionVisitorConcept, typename S>
struct Struct : members_impl<FusionVisitorConcept, S, boost::mpl::int_<0>> {};
} // iteration
template <typename FusionVisitorConcept, typename T>
struct array_application
{
typedef array_application<FusionVisitorConcept, T> type;
typedef typename T::value_type value_type;
static inline void handle(FusionVisitorConcept& visitor, const T& t)
{
visitor.empty_array();
for (auto& el : t)
VisitorApplication<FusionVisitorConcept, value_type>::handle(visitor, el);
}
};
template <typename FusionVisitorConcept, typename T>
struct struct_application
{
typedef struct_application<FusionVisitorConcept, T> type;
static inline void handle(FusionVisitorConcept& visitor, const T& t)
{
visitor.empty_object();
iteration::Struct<FusionVisitorConcept, T>::handle(visitor, t);
}
};
template <typename FusionVisitorConcept, typename T, typename Enable = void>
struct value_application
{
typedef value_application<FusionVisitorConcept, T> type;
static inline void handle(FusionVisitorConcept& visitor, const T& t) {
visitor.value(t);
}
};
template <typename FusionVisitorConcept, typename T>
struct value_application<FusionVisitorConcept, boost::optional<T> >
{
typedef value_application<FusionVisitorConcept, boost::optional<T> > type;
static inline void handle(FusionVisitorConcept& visitor, const boost::optional<T>& t) {
if (t)
VisitorApplication<FusionVisitorConcept, T>::handle(visitor, *t);
else
; // perhaps some default action?
}
};
template <typename FusionVisitorConcept, typename T>
struct select_application
{
typedef
//typename boost::mpl::eval_if<boost::is_array<T>, boost::mpl::identity<array_application<FusionVisitorConcept, T>>,
typename boost::mpl::eval_if<detail::is_vector<T>, boost::mpl::identity<array_application <FusionVisitorConcept, T>>,
typename boost::mpl::eval_if<boost::fusion::traits::is_sequence<T>, boost::mpl::identity<struct_application<FusionVisitorConcept, T>>,
boost::mpl::identity<value_application<FusionVisitorConcept, T>>
> >::type type;
};
} // detail
template <typename FusionVisitorConcept, typename T>
struct VisitorApplication : public detail::select_application<FusionVisitorConcept, T>::type
{
};
}
template <typename FusionVisitorConcept, typename T>
void apply_fusion_visitor(FusionVisitorConcept& visitor, T const& o)
{
visitor::VisitorApplication<FusionVisitorConcept, T>::handle(visitor, o);
}
You can use it by supplying a visitor, e.g. for xml-like output:
struct DisplayMemberVisitor {
typedef std::string result_type;
DisplayMemberVisitor() { ss << std::boolalpha; }
std::string complete() { return ss.str(); }
void start_member (const char* name) {
ss << "<" << name << ">";
}
void finish_member(const char* name) {
ss << "</" << name << ">";
}
template <typename T> void value(T const& value) {
ss << value;
}
void empty_object() { }
void empty_array() { }
private:
std::stringstream ss;
};
See it Live On Coliru where (including some debug output) it prints:
<integer_value>33</integer_value><boolean_value>false</boolean_value><integer_value>34</integer_value><boolean_value>true</boolean_value>
Note that the ADT adaptation macro doesn't include a name (because none is available). You can probably quite easily make a macro FUSION_ADAPT_KEYD_ADT that also accepts a name and generates the relevant specializations of boost::fusion::extension::struct_member_name.
BONUS MATERIAL
Adding member name traits to ADT adapted members
Here's a simplistic approach that shows what little amount of work needs to be done.
#define MY_ADT_MEMBER_NAME(CLASSNAME, IDX, MEMBERNAME) \
namespace boost { namespace fusion { namespace extension { \
template <> struct struct_member_name<CLASSNAME, IDX> { typedef char const *type; static type call() { return #MEMBERNAME; } \
}; } } }
MY_ADT_MEMBER_NAME(Bar, 0, integer_value)
MY_ADT_MEMBER_NAME(Bar, 1, boolean_value)
This defines a macro to avoid most of the repetition. If you are a BOOST_PP whizkid you could somehow weave this into an adt_ex.hpp¹ header of sorts, so you could instead say:
BOOST_FUSION_ADAPT_ADT(Bar, // NOTE THIS PSEUDO-CODE
(integer_value, int, int, obj.get_integer_value(), obj.set_integer_value(val))
(boolean_value, bool, bool, obj.get_boolean_value(), obj.set_boolean_value(val)))
For now here's the ADT adapted trick Live On Coliru
¹ in case you're interested, here's a tarball of a prepared adt_ex tree (drop in alongsize adt.hpp): adt_ex.tgz as a starting point. It's just adt* but with macros and header guards renamed to adt_ex*
Since I discovered boost::lexical_cast all conversions are a breeze. That's until trying to convert a tuples elements into a string. Like Int2String or Double2String I want a way to generate a single string from a tuple of arbitrary number of elements
Since the subject of conversion has arbitrary (yet compile time known) dimension, after some research I've looked into boost::fusion and found this solution :
#include <string>
#include <boost/lexical_cast.hpp>
#include <boost/noncopyable.hpp>
#include <boost/fusion/include/for_each.hpp>
template <class Sequence>
std::string StringFromSequence(const Sequence &seq)
{
std::string result;
boost::fusion::for_each(seq, toString(result));
return result;
}
Where toString is a functor applying the lexical cast to the objects that's been called for :
struct toString: boost::noncopyable
{
explicit toString(std::string& res) : result(res)
{
}
template <class T>
void operator()(const T& v)
{
result += boost::lexical_cast<std::string>(v);
}
private:
std::string &result;
};
When trying to use that though
std::tuple<int, char, double> tup{ 1, 'a', 2.2 };
toString(tup);
I get a compilation error
error C2893: Failed to specialize function template 'enable_if, void>::type boost::fusion::for_each(const Sequence &,const F &)'
Can someone spot and correct the error ?
Are there any (maybe boost free) alternatives ? (it would take compile time recursion and I was hopefully trying to avoid all that boilerplate code)
Since this question is tagged C++11, here's my take at it:
#include <iostream>
#include <string>
#include <tuple>
template<typename T, T...>
struct integer_sequence { };
template<std::size_t N, std::size_t... I>
struct gen_indices : gen_indices<(N - 1), (N - 1), I...> { };
template<std::size_t... I>
struct gen_indices<0, I...> : integer_sequence<std::size_t, I...> { };
template<typename H>
std::string& to_string_impl(std::string& s, H&& h)
{
using std::to_string;
s += to_string(std::forward<H>(h));
return s;
}
template<typename H, typename... T>
std::string& to_string_impl(std::string& s, H&& h, T&&... t)
{
using std::to_string;
s += to_string(std::forward<H>(h));
return to_string_impl(s, std::forward<T>(t)...);
}
template<typename... T, std::size_t... I>
std::string to_string(const std::tuple<T...>& tup, integer_sequence<std::size_t, I...>)
{
std::string result;
int ctx[] = { (to_string_impl(result, std::get<I>(tup)...), 0), 0 };
(void)ctx;
return result;
}
template<typename... T>
std::string to_string(const std::tuple<T...>& tup)
{
return to_string(tup, gen_indices<sizeof...(T)>{});
}
int main(int argc, char** argv)
{
std::tuple<int, double, float> tup(1, 2.1, 3.2);
std::cout << to_string(tup) << std::endl;
}
If you want to stick with boost::lexical_cast, replace to_string with lexical_cast.
Live output on ideone
Sorry but I'm too lazy to enter the details of where you're making the mistakes, but here's a solution using fusion and C++14 polymorphic lambdas:
#include <tuple>
#include <string>
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/fusion/adapted/std_tuple.hpp> // you're missing this huh? it's needed to use fusion with std::tuple
#include <boost/fusion/algorithm/iteration/for_each.hpp>
int main() {
using namespace std;
using namespace boost::fusion;
string result;
for_each(make_tuple(1, 'a', 2.2), [&result](auto &s) {
result += boost::lexical_cast<string>(s) + ' ';
});
cout << result << endl;
}
http://coliru.stacked-crooked.com/a/f110238a317eede9