这是“标签分发”吗? [英] Is this "Tag Dispatching"?

查看:110
本文介绍了这是“标签分发”吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说我有一些代码:

  void barA(){} 
void barB(){}

void fooA(){
//复制代码...
barA();
//更多重复的代码...
}

void fooB(){
//复制代码...
barB();
//更多重复的代码...
}

int main(){
fooA();
fooB();
}

我要删除 fooA之间的重复代码 fooB 我可以使用一些动态技术,例如传递一个bool参数,传递一个函数指针或虚拟方法,编译时技术我可以这样做:

  struct A {}; 
struct B {};

template< typename Tag> void bar();
模板<> void bar< A>(){}
template<> void bar< B>(){}

template< typename标签> void foo(){
//复制代码
bar< Tag>();
//更多重复的代码
}

int main(){
foo< A>();
foo< B>();
}

其中我已经引入了两个空的Tag类来表示 bar 以基于标记类使用和模板化 foo bar 这似乎做的伎俩。问题:


  1. 这种技术有没有名字?这是标签调度的一个例子吗?根据我阅读的有关标记调度的内容,它略有不同,包括函数重载标签参数。

  2. 是否有更多的idomatic编译时技术实现同样的事情?

  3. ol>

    编辑
    另一种可能是使用 bar 并传递标签类作为参数:

      struct A {}; 
    struct B {};

    void bar(A){}
    void bar(B){}

    template< typename Tag> void foo(){
    //复制代码
    bar(Tag());
    //更多重复的代码
    }

    int main(){
    foo< A>();
    foo< B>();
    }


    解决方案

    。正如你在你的问题中说的那样,如果你使用了 A B 的编译时间trait区分两者,然后使用它们在两个不同的重载之间进行选择。



    标签分发的一个很好的例子是 std :: advance 。函数的签名是

     模板< class InputIt,class Distance> 
    void advance(InputIt& it,Distance n);

    it 可以是高级 n 在单个操作中的位置,如果它满足RandomAccessIterator的要求。对于较小的迭代器,我们必须在循环中提前 it 。所以一个实现可能会做类似下面的事情:

     命名空间detail 
    {
    template< class InputIt,class Distance>
    void advance(InputIt& it,Distance n,std :: random_access_iterator_tag)
    {
    it + = n;
    }

    template< class InputIt,class Distance>
    void advance(InputIt& it,Distance n,std :: bidirectional_iterator_tag)
    {
    if(n< 0){
    while(n ++)
    } else {
    while(n--)++ it;
    }
    }

    template< class InputIt,class Distance>
    void advance(InputIt& it,Distance n,std :: input_iterator_tag)
    {
    assert(n> = 0);
    while(n--)++ it;
    }
    }

    template< class InputIt,class Distance>
    void advance(InputIt& it,Distance n)
    {
    detail :: advance(it,n,
    typename std :: iterator_traits< InputIt> :: iterator_category()) ;
    }






    我不知道任何特定的名称,你正在做什么。这只是一个遵循 DRY 原则的示例。



    如果 bar 执行了 A code> B 作为参数,那么我将实现不同。














    $ b

      void bar(A const&){...} 
    void bar(B const&){...}



    但是事实并非如此,提供明确的专业化似乎是正确的方法。


    Say I have some code:

    void barA() { }
    void barB() { }
    
    void fooA() {
      // Duplicate code...
      barA();
      // More duplicate code...
    }
    
    void fooB() {
      // Duplicate code...
      barB();
      // More duplicate code...
    }
    
    int main() {
      fooA();
      fooB();
    }
    

    And I want to remove the duplicate code between fooA and fooB I could use a number of dynamic techniques such as passing in a bool parameter, passing a function pointer or virtual methods but if I wanted a compile time technique I could do something like this:

    struct A { };
    struct B { };
    
    template<typename Tag> void bar();
    template<> void bar<A>() { }
    template<> void bar<B>() { }
    
    template<typename Tag> void foo() {
      // Duplicate code
      bar<Tag>();
      // More duplicate code
    }
    
    int main() {
      foo<A>();
      foo<B>();
    }
    

    where I have introduced two empty "Tag" classes to indicate which bar to use and templated foo and bar based on the tag class. This seems to do the trick. Questions:

    1. Does this technique have a name? is this an example of "Tag dispatching"? From what I read about Tag dispatching it is slightly different and involves function overloading with a tag parameter. A tag that may have come from a typedef in a trait class.
    2. Is there a more idomatic compile-time technique of achieving the same thing?

    Edit: Another possibility would be to use function overloading of bar instead of template specialization and pass the tag class as a parameter:

    struct A { };
    struct B { };
    
    void bar(A) { }
    void bar(B) { }
    
    template<typename Tag> void foo() {
      // Duplicate code
      bar(Tag());
      // More duplicate code
    }
    
    int main() {
      foo<A>();
      foo<B>();
    }
    

    解决方案

    This isn't tag dispatching. As you rightly said in your question, that'd be if you used some compile time trait of A and B to distinguish between the two, and then use that to select between two different overloads.

    An good example of tag dispatch would be how std::advance is typically implemented. The function's signature is

    template< class InputIt, class Distance >
    void advance( InputIt& it, Distance n );
    

    it can be advanced n positions in a single operation if it meets the requirements of RandomAccessIterator. For lesser iterators we must advance it in a loop. So an implementation would probably do something similar to the following:

    namespace detail
    {
      template<class InputIt, class Distance>
      void advance(InputIt& it, Distance n, std::random_access_iterator_tag) 
      {
        it += n;
      }
    
      template<class InputIt, class Distance>
      void advance(InputIt& it, Distance n, std::bidirectional_iterator_tag) 
      {
        if(n < 0) {
          while(n++) --it;
        } else {
          while(n--) ++it;
        }
      }
    
      template<class InputIt, class Distance>
      void advance(InputIt& it, Distance n, std::input_iterator_tag) 
      {
        assert(n >= 0);
        while(n--) ++it;
      }
    }
    
    template< class InputIt, class Distance >
    void advance( InputIt& it, Distance n )
    {
      detail::advance(it, n, 
                      typename std::iterator_traits<InputIt>::iterator_category());
    }
    


    I don't know of any specific name for what you're doing. It's just an example of how one would follow the DRY principle.

    If bar took an instance of A and B as an argument, then I'd implement this differently. Instead of making bar a function template, and then providing specializations, I'd let overload resolution do the job for me.

    void bar(A const&) { ... }
    void bar(B const&) { ... }
    

    But since that's not the case, providing explicit specializations seems the right way to do this.

    这篇关于这是“标签分发”吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆