我最近遇到了一种基于数据类型“概念”的调度模式(我认为正确使用术语概念,如果没有,属性?)。
在我看来,比我之前见过的事情要多一点,至少在优化之前,介绍了临时变量和函数调用。我的问题是(1)它是否真的被优化了? (2)这是做这种基于类型的调度的“最佳”方式吗?
我正在阅读的代码处理迭代器类型,所以我将坚持使用它作为模式的一个例子。下面的函数iter_kind
接受任何类型的变量,并返回特定“概念”类型的虚拟变量。像random_access_iterator_kind
这样的东西,或者_Iter
是非迭代器类型null_iterator_kind
。
template <typename _Iter>
INLINE_CALL typename iterator_traits<_Iter>::iter_kind iter_kind(_Iter&)
{
typename iterator_traits<_Iter>::iter_kind _ret;
return ( _ret );
}
它通过iterator_traits
类的专业化使用通常的元魔法。我很满意这些东西。
iter_kind
习惯于委托给特定函数的不同实现,例如:
template <typename _Iter, typename _Pred>
_Iter binary_search(_Iter head, _Iter tail, _Pred pred_less)
{
binary_search_impl(head, tail, pred_less, iter_kind(head));
}
template <typename _Iter, typename _Pred>
_Iter binary_search_impl(_Iter head, _Iter tail, _Pred pred_less,
random_access_iterator_kind)
{ // actual implementation...
}
template <typename _Iter, typename _Pred>
_Iter binary_search_impl(_Iter head, _Iter tail, _Pred pred_less,
bidirectional_iterator_kind)
{
assert(false); // can't do bin search without random access iters!!
}
答案 0 :(得分:1)
是的,这些东西确实都得到了优化。编译器是专门编写的,以便在完成之后摆脱这个垃圾,因为这是一个常见的技巧。这种方式完成了函数和重载,因为它比任何其他方式更容易实现。这是标准库实现中常用的技巧。
答案 1 :(得分:0)
嗯,不,这不是最好的方式。您可以在编译时选择正确的重载,例如:
template <typename _Iter, typename _Pred>
_Iter binary_search(_Iter head, _Iter tail, _Pred pred_less)
{
binary_search_impl(head, tail, pred_less,
std::iterator_traits<_Iter>::iterator_category());
}
更好的方法是在实际函数的签名中使用SFINAE,在运行时零开销:基本上你在迭代器类别上使用std::enable_if
来告诉编译器选择哪个重载。 / p>