关于boost mpl占位符的推理
Reasoning about boost mpl placeholders
Boost MPL库文档的教程:元函数和高阶元编程部分指出,transform
可以像一样调用
typename mpl::transform<D1,D2, mpl::minus<_1,_2> >::type
其中占位符_1
和_2
表示当调用变换的BinaryOperation
时,它的第一个和第二个自变量将分别在_1
和_2
指示的位置上传递到minus。
我已经一遍又一遍地读了将近一个月了,但我仍然不明白
占位符_1
和_2
究竟有什么值?CCD_ 9和CCD_?如果是,为什么不写mpl::minus<D1,D2>
?还考虑到占位符被定义为typedef arg<1> _1;
和typedef arg<2> _2;
,因此在我看来的原始表达式相当于
typename mpl::transform<D1,D2, mpl::minus<<arg<1>,<arg<2> > >::type
我肯定我想占位符的方式不对。我很感激这里的指导。
实际上,您对占位符的考虑是错误的。
mpl::minus
是MPL元语言中的一个模板,它象征性地表示(或对应)某种高级行为,即减法。你认为它是一个非元结构,比如函数
int minus(int a, int b) { return a - b; }
但事实并非如此。(标准C++11库确实有类似的东西,称为std::minus<>
,但这是而不是mpl::minus
的功能!)
mpl::minus
表示在更高抽象级别上的减法运算。关于mpl::minus
是如何实现的,请不要担心接下来的几段内容。想想它代表什么,这是两件事的减法。
啊,但是哪两件事?mpl::minus
允许您将这些内容指定为模板参数。例如,
mpl::minus<mpl::int_<7>, mpl::int_<3>>
扩展为成员typedef type
与CCD_。
好吧,但在Boost的维度分析示例中,他们不仅仅有两件事;它们具有序列CCD_ 22和CCD_。(这是非常重要的一点!)减去序列与减去integers不是一回事;考虑
auto a = std::vector<int>{ 1, 0, 0 };
auto b = std::vector<int>{ 0, 1, 0 };
auto c = (a - b); // Won't compile!
同样,在元空间中,
using a = mpl::vector<mpl::int_<1>, mpl::int_<0>, mpl::int_<0>>;
using b = mpl::vector<mpl::int_<1>, mpl::int_<0>, mpl::int_<0>>;
using c = mpl::minus<a,b>; // Won't compile!
我们的意思说,在第一种情况下,是
auto c = std::vector<int>{};
std::transform(a.begin(), a.end(), b.begin(), std::back_inserter(c), std::minus<>{});
在第二种(元)情况下,我们的意思是
using c = mpl::transform<a, b, mpl::minus>::type; // caveat: we're not done yet
注意,C++11std::transform
采用了成对的迭代器a.begin(), a.end()
,而不仅仅是a
;它需要CCD_ 27而不是CCD_;并且为了提高效率,它通过输出迭代器对c
进行变异,而不是返回一个全新的对象。MPL的编译时元版本直接获取容器a
和b
,并返回一个新的容器c
,即它具有值语义,IMHO更容易考虑这一点。
所以,以上都是正确的,除了一个小细节!mpl::transform
实际上是一个非常通用的算法,这意味着它希望您拼写出转换的细节。你说"mpl::minus
",意思是"减法",好吧,但从什么中减去什么?从第二序列的元素中减去第一序列的元素?从第一个元素中减去第二个元素?从第二个序列的元素中减去42
,并完全抛出第一个序列?
好吧,我们的意思是"从第一个序列中减去第二个序列的元素。"我们把它写成
using c = mpl::transform<a, b, mpl::minus<_1, _2>>::type;
我们同样可以写
using c = mpl::transform<b, a, mpl::minus<_2, _1>>::type;
--这意味着完全相同的事情。
这种通用的transform
算法使我们能够编写复杂的变换,如
// hide some irrelevant boilerplate behind an alias
template<typename... Ts>
using multiplies_t = mpl::multiplies<Ts...>::type;
// compute c = a^2 + 2ab + 1
using c = mpl::transform<a, b,
mpl::plus<multiplies_t< _1, _1 >, // a^2 ...
multiplies_t< mpl::int_<2>, _1, _2 >, // ... + 2ab ...
mpl::int_<1>> // ... + 1
>::type;
在这里,我们可以使用符号_1
来三次引用序列a
的相同元素,而_2
指代序列b
的相应元素。
这就是符号_1
和_2
在mpl::transform
上下文中的点。但你可能仍然想知道它们是如何实现的。这里没有魔法。它们也可以作为来实现
template<int> struct _ {};
using _1 = _<1>;
using _2 = _<2>;
只要它们在C++的类型系统中得到唯一的、可区分的实体,这就是MPL真正关心的。
但事实上,它们实际上被实现为mpl::arg
专业化的typedef,这导致了一个巧妙的技巧。由于_1
是mpl::arg<1>
的同义词,我们可以说
_1::apply<A,B,C>::type is the same type as A
_2::apply<A,B,C>::type is the same type as B
...
我猜想CCD_ 47能够在内部利用这一事实。
- 将模板与类模板扣除占位符参数匹配
- C++初始化 std::function 时如何将占位符绑定到引用/引用参数?
- Tensorflow C++ 占位符初始化
- std::bind 不会接受 bind 占位符的 std::cref - 为什么?
- qt 中的占位符
- 我可以在 c++ 中使用占位符作为数组的索引吗?
- 为什么协程不允许使用占位符返回类型?
- TensorFlow类占位符以及其他定义输入张量的方法
- QtLineEdit 占位符:如何让用户在插入模式下将字符 1 替换为 1
- 非类型模板参数中的占位符类型是否涉及作为模板参数传递的函数的重载解析?
- 是否可以使用自动占位符来推断非类型模板参数中的函数结果
- 如何使用 msgfmt 验证格式字符串中的位置表示法占位符
- 无法推断出占位符的概念
- 编译器错误boost :: asio ::占位符:: boost v1.69的错误
- std::绑定可变参数模板、绑定参数和占位符
- 尾随返回类型中的占位符类型的用途是什么
- 如何在折叠过程中获取成员类型的提升::mpl 占位符
- 将具有任意参数和占位符的函数存储在类中,然后再调用它
- 回调中的占位符_1是如何工作的
- 关于boost mpl占位符的推理