我正在查看一些与n3960
标准提案有关的代码,并注意到某些函数具有不带名称的参数,但具有完整的函数定义。有人可以解释这是怎么回事吗?
例:
template <typename ExPolicy, typename IteratorTag>
void test_for_each(ExPolicy const& policy, IteratorTag) //just IteratorTag, no name?
{
BOOST_STATIC_ASSERT(hpx::parallel::is_execution_policy<ExPolicy>::value);
typedef std::vector<std::size_t>::iterator base_iterator;
typedef test::test_iterator<base_iterator, IteratorTag> iterator;
std::vector<std::size_t> c(10000);
std::iota(boost::begin(c), boost::end(c), std::rand());
hpx::parallel::for_each(policy,
iterator(boost::begin(c)), iterator(boost::end(c)),
[](std::size_t& v) {
v = 42;
});
// verify values
std::size_t count = 0;
std::for_each(boost::begin(c), boost::end(c),
[](std::size_t v) {
HPX_TEST_EQ(v, std::size_t(42));
++count;
});
HPX_TEST_EQ(count, c.size());
}
如前所述,参数名称是可选的。但是,为什么忽略了这一点?为什么有一个没有名称的参数呢?
这里使用的技术是基于参数类型的功能模板标签类型推导。
您可以调用test_for_each
传入任意类型的实例作为第二个参数。无论该参数的值类型是什么,最终都会以形式传递给template
函数IteratorTag
。
在类中,IteratorTag
不使用变量的值-我们只关心类型。
IteratorTag
s用于区分各种std
库迭代器-转发,随机访问,输入,输出等。
有了该类型,我们就可以对代码的行为进行细微的更改(或者使用重载来进行细微的更改)。在这种情况下,iterator
函数中的IteratorTag
类型将类型作为其template
参数之一,因此该变量的类型根据IteratorTag
传入的内容而有所不同。
这是使用标记的一种简单版本,该标记称为“标记分配”技术:
template<typename T>
int floor_to_int( T&& t, std::true_type ) { return std::forward<T>(t); }
template<typename T>
int floor_to_int( T&& t, std::false_type ) { return floor(std::forward<T>(t)); }
template<typename T>
int smart_floor( T&& t ) {
return floor_to_int( std::forward<T>(t), std::is_integral< typename std::decay<T>::type >{} );
}
在这里,该smart_floor
函数采用任意类型T
,并且仅当它是非整数类型时才对其进行调用floor
。否则,它只会将其转换为int
。
我们创建标签类型的实例(在这种情况下为),std::is_integral< typename std::decay<T>::type >
并将其传递给内部帮助函数。在这种情况下,我们有两个重载,两个重载都不使用传递的标记的值,仅使用其类型。
上面的实现是相似的,除了在两种情况下都有1个重载。也许该标签类型将以类似的重载方式更深入地使用,或者它可能在某些特质类中以更深层次的使用专门化。
顺便说一句,这里的论点应该是赔率std::iterator_traits< T >::iterator_category
或一些自制的boost
变体。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句