【问题标题】:BOOST_FUSION_ADAPT_TPL_STRUCT and template array sizeBOOST_FUSION_ADAPT_TPL_STRUCT 和模板数组大小
【发布时间】:2013-04-04 10:04:28
【问题描述】:

感谢BOOST_FUSION_ADAPT_TPL_STRUCT,我正在尝试迭代 C++ 模板结构。我的结构包含固定大小的多维数组,其大小是模板参数。如果我们考虑修改 Boost 的示例以适应我的问题:

#include <iostream>
#include <string>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

// Example:
// http://www.boost.org/doc/libs/1_53_0/libs/fusion/doc/html/fusion/adapted/adapt_tpl_struct.html

namespace demo
{
    template<typename T, unsigned int SIZE1, unsigned int SIZE2, typename Name, typename Age>
    struct employee
    {
        Name name;
        Age age;
        T ar[SIZE1][SIZE2];
    };
}

// Any instantiated demo::employee is now a Fusion sequence
BOOST_FUSION_ADAPT_TPL_STRUCT(
    (T)(SIZE1)(SIZE2)(Name)(Age),
    (demo::employee) (T)(SIZE1)(SIZE2)(Name)(Age),
    (Name, name)
    (Age, age)
    (T, ar[SIZE1][SIZE2]))

int main()
{
    demo::employee<float, 2, 2, std::string, int> e;
    e.name = "Bob";
    e.age = 25;
    e.ar[0][0] = e.ar[1][0] = 0.1;
    e.ar[0][1] = e.ar[1][1] = 0.2;
}

编译失败。此外,如果我们只添加一个整数模板参数而不使用它作为数组大小,它也会失败。

BOOST_FUSION_ADAPT_TPL_STRUCT 也可以吗?如果没有,我该怎么办?

【问题讨论】:

    标签: c++ templates boost struct boost-fusion


    【解决方案1】:

    在与 Evgeny Panasyuk 进行了长时间的交谈后,我最终做了一些不同的事情。由于我希望能够对数据结构进行一些简单的算术运算,因此我决定使用Eigen::Map 而不是Boost::multi_array,因为它提供了广泛的运算符以及清晰的文档。

    因此,较高级别的循环由boost::fusion::for_each 处理,较低级别的循环由 Eigen 处理。数组线性映射到特征向量。大小在data_eigen 的构造函数中传递。

    #include <iostream>
    
    #include <boost/fusion/adapted/struct/adapt_struct.hpp>
    #include <boost/fusion/include/adapt_struct.hpp>
    #include <boost/fusion/algorithm/iteration/for_each.hpp>
    #include <boost/fusion/include/for_each.hpp>
    #include <boost/bind.hpp>
    
    #include <Eigen/Core>
    
    namespace demo
    {
    template<typename T, int SIZE1, int SIZE2>
    struct data
    {
        T ar1[SIZE1][SIZE2];
        T ar2[SIZE1][SIZE2];
    };
    
    template<typename T>
    struct EigenMap
    {
        typedef Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, 1> > type;
    };
    
    template<typename T>
    struct data_eigen
    {
        template <int SIZE1, int SIZE2>
        data_eigen(data<T,SIZE1,SIZE2>& src)
            : ar1(typename EigenMap<T>::type(&src.ar1[0][0], SIZE1*SIZE2)),
              ar2(typename EigenMap<T>::type(&src.ar2[0][0], SIZE1*SIZE2))
        {
        }
    
        typename EigenMap<T>::type ar1;
        typename EigenMap<T>::type ar2;
    };
    
    
    struct print
    {
        template<typename T>
        void operator()(const Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, 1> >& t) const
        {
            std::cout << t.transpose() << std::endl;
        }
    };
    
    struct scalarMult
    {
        template<typename T, typename U>
        void operator()(T& t, U& u) const
        {
            t *= u;
        }
    };
    
    }
    
    BOOST_FUSION_ADAPT_TPL_STRUCT
    (
        (T),
        (demo::data_eigen) (T),
        (typename demo::EigenMap<T>::type, ar1)
        (typename demo::EigenMap<T>::type, ar2)
    )
    
    int main()
    {
        typedef float REALTYPE;
        const int SIZE1 = 2;
        const int SIZE2 = 2;
    
        // Basic data structure with multidimensional arrays
        demo::data<REALTYPE, SIZE1, SIZE2> d;
        for (unsigned int i = 0; i < SIZE1; ++i)
            for (unsigned int j = 0; j < SIZE2; ++j)
            {
                d.ar1[i][j] = (i+1)*(j+1);
                d.ar2[i][j] = i + j;
            }
    
        // Eigen::Map + BOOST_FUSION_ADAPT_TPL_STRUCT
        demo::data_eigen<REALTYPE> eig_d(d);
    
        std::cout << "d:" << std::endl;
        boost::fusion::for_each(eig_d, demo::print());
        std::cout << std::endl;
    
        boost::fusion::for_each(eig_d, boost::bind<void>(demo::scalarMult(), _1, 2.0));
        std::cout << "2 * d:" << std::endl;
        boost::fusion::for_each(eig_d, demo::print());
        std::cout << std::endl;
    }
    

    【讨论】:

      【解决方案2】:

      来自doc

      序列 (template_param0)(template_param1)... 声明了使用的模板类型参数的名称

      虽然你有非类型模板参数 SIZE:

      template<typename T, unsigned int SIZE, typename Name, typename Age>
      struct employee
      

      您可以将其转换为类型模板参数并使用boost::mpl::int_ 作为进位大小的包装器。

      现在,您的代码是 compiled

      template<int Size>
      struct Array
      {
          template<typename T>
          struct Of
          {
              typedef T type[Size];
          };
      };
      
      namespace demo
      {
          template<typename T, typename SIZE, typename Name, typename Age>
          struct employee
          {
              Name name;
              Age age;
              T ar[SIZE::value];
          };
      }
      
      // Any instantiated demo::employee is now a Fusion sequence
      BOOST_FUSION_ADAPT_TPL_STRUCT(
          (T)(SIZE)(Name)(Age),
          (demo::employee) (T)(SIZE)(Name)(Age),
          (Name, name)
          (Age, age)
          (typename Array<SIZE::value>::template Of<T>::type, ar))
      
       //...
       demo::employee<float, int_<2>, std::string, int> e;
      

      【讨论】:

      • 好的,谢谢您的回答!我想我必须看看使用BOOST_FUSION_ADAPT_TPL_STRUCT 是否值得在我的库中进行一些重构。
      • 不客气!如果合适的话,也许你也应该考虑BOOST_FUSION_DEFINE_TPL_STRUCT,以减少重复。
      • 我正在研究的数据结构用于使用 CUDA 进行 GPGPU 计算。我想我必须检查nvcc 是否可以正确处理这些 Boost 生成的结构。
      • 注意,我更新了答案——包括数组大小在内的所有类型信息都应该作为第一个参数。
      • 我明白了,我想这是BOOST_FUSION_DEFINE_TPL_STRUCT 的要求。然后,我会将您的代码调整为 n 维数组。还是我应该试试Boost.MultiArray
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多