模板元魔法

发布于 2024-11-05 19:07:30 字数 1394 浏览 0 评论 0原文

我最近遇到了一种基于数据类型“概念”的调度模式(我认为这是术语概念的正确使用,如果不是,属性??)。

在我看来,它比我以前见过的类型更复杂,至少在优化之前,引入了临时变量和函数调用。我的问题是(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!!
    }

I recently came across a kind of dispatch pattern based on the "concepts" of the data types (I think that's the correct use of the term concepts, if not, attributes??).

It seems to me to be a bit more involved than the type of thing I've seen before, and before optimisation at least, introduces temporary variables and function calls. My question is (1) does it all actually get optimised away?? (2) is this the "best" way of doing this kind of type based dispatch??

The code I was reading dealt with iterator types, so I'll stick with that as an example of the pattern. The function iter_kind below takes a variable of any type and returns a dummy variable of a particular "concept" type. Something like random_access_iterator_kind, or if _Iter was a non-iterator type 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 );
}

It works using the usual meta-magic via specialisation of the iterator_traits class. I'm happy with all that stuff.

iter_kind gets used to delegate to different implementations of a particular function, as an example:

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!!
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

默嘫て 2024-11-12 19:07:30

是的,这些东西确实都被优化掉了。编译器是专门为在完成后消除这些垃圾而编写的,因为这是一个常见的技巧。以这种方式完成函数和重载是因为,它比任何其他方式都要容易得多。这是标准库实现中常用的技巧。

Yes, this stuff really does all get optimized away. Compilers are written specifically to get rid of this gunk after it's done, because it's a common trick. Functions and overloading this way are done because, well, it's simply a lot easier than doing it any other way. This is a common trick used in the implementation of the Standard library.

音盲 2024-11-12 19:07:30

嗯,不,这不是最好的方法。您可以在编译时选择正确的重载,如下所示:

 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 在任一迭代器类别上告诉编译器选择哪个重载。

Well, no, it's not the best way. You can select the correct overload at compile time like this, for example:

 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());    
   }

Even better way is to use SFINAE in the signature of the actual function, with zero overhead at run-time: basically you'd use std::enable_if on either iterator category to tell the complier which overload to pick.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文