【问题标题】:Boost mpl transformed sequence "real" typeBoost mpl 变换序列“真实”类型
【发布时间】:2013-02-19 18:49:50
【问题描述】:

请参阅 boost mpl 转换文档中的以下代码:

typedef vector<char,short,int,long,float,double> types;
typedef vector<char*,short*,int*,long*,float*,double*> pointers;
typedef transform< types,boost::add_pointer<_1> >::type result;
BOOST_STATIC_ASSERT(( equal<result,pointers>::value ));

我想了解boost::mpl 的类型系统以及“它实际上是如何工作的”。 据我了解mpl::equal 只是比较以下两个序列的元素,而不是整个序列类型本身。 我不明白为什么以下失败:

BOOST_STATIC_ASSERT(( std::is_same<result,pointers>::value )); //< assert fails

为什么结果类型与“指针”类型不是 100% 相同? 我认为这是因为 mpl 正在执行转换惰性或结果只是一个序列而不是向量? 是否有可能以某种方式强制 mpl 不再偷懒并获得 100% 相同的类型(我可以用这个结果自己编写一个转换函数,但我想知道如何在 mpl 中做到这一点)?

我已经尝试了一些东西,例如将结果插入新向量但没有成功:

BOOST_STATIC_ASSERT(( std::is_same<
  mpl::insert_range< mpl::vector<>, mpl::begin<mpl::vector<> >::type,
  result >::type, pointers >::value )); //< assert fails too

另外,我尝试在转换函数中使用 back_insert,但也失败了:

typedef transform< types,boost::add_pointer<_1>,
  mpl::back_inserter< mpl::vector< > > >::type result_new;
BOOST_STATIC_ASSERT(( std::is_same<result_new,pointers>::value )); //< fails...

阅读“文档”对我没有帮助。 再说一遍,是否有可能使用 mpl 变换(或任何其他变换序列函数)获得 100% 相同的类型?以及类型的结果是什么

result

“在现实中”当它与指针不同时?

【问题讨论】:

  • 我猜那是boost::mpl::vector 而不是std::vector?小心using 指令,否则您可能会遇到冲突,或者在最坏的情况下,代码难以遵循和维护。
  • @JoachimPileborg thx 指出这一点,它是关于 boost::mpl::vector (代码来自教程,我不想修改它)。请注意,我在其余代码中使用别名 namespace mpl = boost::mpl;
  • @llonesmiz 非常感谢您的代码,它确实有助于调试 boost::mpl 的使用!所以原始类型是boost::mpl::vector 与转换后的嵌套类型boost::mpl::v_item。我仍然想知道是否可以将 v_time 转换回 mpl::vector。至少我现在可以编写自己的转换函数了……
  • @llonesmiz 在代码粘贴时从 g++ 切换到 intel 编译器后,all 结果类型更改为 boost::mpl::vector6&lt;char*, short*, int*, long*, float*, double*&gt;,这与 pointers 类型相同(只需使用 @987654338 @ 而不是 mpl::vector&lt;&gt;) : )。所以实际上在这种情况下类型被转换回 vector6 ,这使得它与手写指针类型相同。一些想法:在一般情况下(不使用 c++11 中的可变参数类型),反向转换是不可能的,因为 vectorN 总是有一个最大数 N 并且转换具有额外的编译成本。

标签: c++ templates boost boost-mpl


【解决方案1】:

再次感谢 @llonesmiz 提供使用 typeid() 漂亮地打印类型的代码,这有助于了解正在发生的事情。

所以看起来真正的结果类型取决于编译器(可能是 boost #ifdefs),intel 编译器和 Visual Studio 将它转换回 std::vectorN 其中最大 N 是 boost 中的预定义数字(所以它确实N太大时不起作用)。 对于 g++,会生成一个重整类型(甚至是来自我的转换调用的 2 种不同类型)。

所以我想通过 mpl::equal 检查类型很好(检查范围的元素)。 如果所有类型都应该“真正”等效(std::is_same 成立),我想您需要手动将结果转换为可变参数模板类 std::tuple。

http://liveworkspace.org/code/3l8O9K$16 Code Sample

或者简而言之:

template < class T, class R >
struct ToStdTuple;

template < class... TTypes, class X >
struct ToStdTuple< std::tuple< TTypes... >, X >
{
  typedef std::tuple< TTypes..., X > type;
};

然后

// typedef mpl::vector<char,short,int,long,float,double> types;
// typedef mpl::transform< types,boost::add_pointer<mpl::_1> >::type result;

typedef mpl::fold< result, std::tuple<>,
  ToStdTuple< mpl::_1, mpl::_2 > >::type result_normalized;

导致

std::tuple<char*, short*, int*, long*, float*, double*>

对于所有转换调用

【讨论】:

  • 非常干净的解决方案,可以将任何boost::mpl 序列转换为std::tuple+1
  • 这实际上是将任何boost::mpl 序列转换为特定序列类型的完美解决方案...例如boost::python::bases,这是我的目标。不幸的是,我正在使用的 VS2010 不支持可变参数模板,但我已经能够通过 Boost.Preprocessor 解决这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多