C++ 使用boost::fusion进行迭代时,将漂亮的打印机绑定到boost::phoenix actors

C++ 使用boost::fusion进行迭代时,将漂亮的打印机绑定到boost::phoenix actors,c++,boost,metaprogramming,boost-fusion,boost-phoenix,C++,Boost,Metaprogramming,Boost Fusion,Boost Phoenix,这个问题是被接受的解决方案在哪里起作用的后续问题 现在,我不仅想将(原语)值添加到属性映射中,还想使用漂亮的打印机来改进值的显示方式。如果打印的值不是微不足道的,也将使用此机制 所以,有一些漂亮的打印机是这样的: template<typename T> std::string prettyPrinter(const T& t); template<> std::string prettyPrinter(const std::string& s) {

这个问题是被接受的解决方案在哪里起作用的后续问题

现在,我不仅想将(原语)值添加到属性映射中,还想使用漂亮的打印机来改进值的显示方式。如果打印的值不是微不足道的,也将使用此机制

所以,有一些漂亮的打印机是这样的:

template<typename T>
std::string prettyPrinter(const T& t);

template<>
std::string prettyPrinter(const std::string& s)
{
    return "The string id: " + s;
}

template<>
std::string prettyPrinter(const int& i)
{
    return "The int id: " + std::to_string(i);
}

我现在寻找的是一个更优雅的解决方案的可能性,因为@sehe在评论中指出,在这里使用
phoenix::bind
可能不是最佳选择。

您显示的代码中有一些随机错误。没有一个
prettyPrinter
重载可以编译。没有
Seq
这样的东西。您可以为不存在的成员调整结构

撇开所有这些不谈,您在这里的竞争是一条次优路线:函数模板和专门化不能很好地混合(ª)

你似乎有意硬编码你的类型以及漂亮的打印逻辑

咒语

类型推断和ADL是可扩展机制的朋友

我将编写漂亮的打印界面,大致如下:

#include <string>

namespace pretty_printing
{
    namespace default_impl {
        std::string do_pretty_print(const std::string& s) {
            return "The string id: " + s;
        }

        std::string do_pretty_print(const int i) {
            return "The int id: " + std::to_string(i);
        }
    }

    struct pretty_print_f {
        using result_type = std::string;

        template <typename T> result_type operator()(T&& v) const { 
            using namespace default_impl; // enable ADL
            return do_pretty_print(std::forward<T>(v));
        }
    };
}
简化的关键是让编译器做它最擅长的事情:使用推导的参数类型进行重载解析

完整演示

#include <string>

namespace pretty_printing
{
    namespace default_impl {
        std::string do_pretty_print(const std::string& s) {
            return "The string id: " + s;
        }

        std::string do_pretty_print(const int i) {
            return "The int id: " + std::to_string(i);
        }
    }

    struct pretty_print_f {
        using result_type = std::string;

        template <typename T> result_type operator()(T&& v) const { 
            using namespace default_impl;
            return do_pretty_print(std::forward<T>(v));
        }
    };
}

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/find.hpp>
#include <boost/phoenix/fusion/at.hpp>
#include <boost/phoenix.hpp>
#include <boost/mpl/range_c.hpp>

#include <iostream>

struct Vertex {
    std::string id;
    int numeric_value;
};

struct Edge {
    int more;
    std::string awesome_sauce;
};

BOOST_FUSION_ADAPT_STRUCT(Vertex, id, numeric_value)
BOOST_FUSION_ADAPT_STRUCT(Edge, more, awesome_sauce)

template <typename Tag, typename T_Graph>
void member_iterator(boost::dynamic_properties& dp, T_Graph& g)
{
    using namespace boost;
    namespace px = boost::phoenix;
    using namespace px::arg_names;

    using Bundle = typename property_map<T_Graph, Tag>::type;
    using T_Seq  = typename property_traits<Bundle>::value_type;

    using Indices = mpl::range_c<unsigned, 0, fusion::result_of::size<T_Seq>::value>;

    fusion::for_each(
        Indices{},
        [&, bundle=get(Tag{}, g)](auto i) {

            auto name = fusion::extension::struct_member_name<T_Seq, i>::call();
            px::function<pretty_printing::pretty_print_f> pretty_print;

            dp.property(
                name,
                make_transform_value_property_map(pretty_print(px::at_c<i>(arg1)), bundle)
            );
        }
    );
}

using MyGraph = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, Vertex, Edge>;

int main()
{
    MyGraph g;
    boost::dynamic_properties dp;

    member_iterator<boost::vertex_bundle_t>(dp, g);
    member_iterator<boost::edge_bundle_t>(dp, g);
}
#包括
名称空间打印
{
名称空间默认值{
std::string打印(const std::string&s){
返回“字符串id:+s;
}
std::字符串打印(const int i){
返回“intid:+std::to_字符串(i);
}
}
结构漂亮的打印{
使用result_type=std::string;
模板结果类型运算符()(T&&v)常量{
使用名称空间默认值\u impl;
返回打印(标准::转发(v));
}
};
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
结构顶点{
std::字符串id;
int数值;
};
结构边{
int更多;
std::丝状酱汁;
};
BOOST\u FUSION\u ADAPT\u结构(顶点、id、数值)
增强融合适应结构(边缘,更多,很棒的酱汁)
模板
void成员迭代器(boost::dynamic_属性&dp,T_图&g)
{
使用名称空间boost;
名称空间px=boost::phoenix;
使用名称空间px::arg_名称;
使用Bundle=typename属性\映射::type;
使用T_Seq=typename属性_traits::value_type;
使用索引=mpl::range\u c;
fusion::针对每个(
指数{},
[&,bundle=get(Tag{},g)](自动i){
auto name=fusion::extension::struct_member_name::call();
px::函数漂亮的打印;
dp.财产(
名称
生成_变换_值_属性_映射(漂亮打印(px::at_c(arg1)),捆绑)
);
}
);
}
使用MyGraph=boost::邻接列表;
int main()
{
myg图;
boost::动态_属性dp;
成员迭代器(dp,g);
成员迭代器(dp,g);
}


也请参见GotW#49和例如

,这大大改进了我的实际代码!我一定会阅读你的资料,谢谢!
auto name = fusion::extension::struct_member_name<T_Seq, i>::call();
px::function<pretty_printing::pretty_print_f> pretty_print;

dp.property(
    name,
    make_transform_value_property_map(pretty_print(px::at_c<i>(arg1)), bundle)
);
#include <string>

namespace pretty_printing
{
    namespace default_impl {
        std::string do_pretty_print(const std::string& s) {
            return "The string id: " + s;
        }

        std::string do_pretty_print(const int i) {
            return "The int id: " + std::to_string(i);
        }
    }

    struct pretty_print_f {
        using result_type = std::string;

        template <typename T> result_type operator()(T&& v) const { 
            using namespace default_impl;
            return do_pretty_print(std::forward<T>(v));
        }
    };
}

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/find.hpp>
#include <boost/phoenix/fusion/at.hpp>
#include <boost/phoenix.hpp>
#include <boost/mpl/range_c.hpp>

#include <iostream>

struct Vertex {
    std::string id;
    int numeric_value;
};

struct Edge {
    int more;
    std::string awesome_sauce;
};

BOOST_FUSION_ADAPT_STRUCT(Vertex, id, numeric_value)
BOOST_FUSION_ADAPT_STRUCT(Edge, more, awesome_sauce)

template <typename Tag, typename T_Graph>
void member_iterator(boost::dynamic_properties& dp, T_Graph& g)
{
    using namespace boost;
    namespace px = boost::phoenix;
    using namespace px::arg_names;

    using Bundle = typename property_map<T_Graph, Tag>::type;
    using T_Seq  = typename property_traits<Bundle>::value_type;

    using Indices = mpl::range_c<unsigned, 0, fusion::result_of::size<T_Seq>::value>;

    fusion::for_each(
        Indices{},
        [&, bundle=get(Tag{}, g)](auto i) {

            auto name = fusion::extension::struct_member_name<T_Seq, i>::call();
            px::function<pretty_printing::pretty_print_f> pretty_print;

            dp.property(
                name,
                make_transform_value_property_map(pretty_print(px::at_c<i>(arg1)), bundle)
            );
        }
    );
}

using MyGraph = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, Vertex, Edge>;

int main()
{
    MyGraph g;
    boost::dynamic_properties dp;

    member_iterator<boost::vertex_bundle_t>(dp, g);
    member_iterator<boost::edge_bundle_t>(dp, g);
}