c++ - 这是 "Tag Dispatching"吗?

标签 c++ templates c++11 template-meta-programming

假设我有一些代码:

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

void fooA() {
  // Duplicate code...
  barA();
  // More duplicate code...
}

void fooB() {
  // Duplicate code...
  barB();
  // More duplicate code...
}

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

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

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

我引入了两个空的“Tag”类来指示使用哪个 bar 并根据标签类模板化 foobar .这似乎可以解决问题。问题:

  1. 这项技术有名字吗?这是“标签调度”的例子吗?从我读到的Tag dispatching它略有不同,涉及使用标记参数的函数重载。可能来自特征类中的 typedef 的标记。
  2. 是否有更通用的编译时技术来实现相同的目的?

编辑: 另一种可能性是使用 bar 的函数重载而不是模板特化并将标记类作为参数传递:

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

最佳答案

这不是标签分发。正如您在问题中正确所说的那样,如果您使用 AB 的某些编译时特征来区分两者,然后使用它来进行选择两种不同的重载。

标签分派(dispatch)的一个很好的例子是如何 std::advance通常被实现。该函数的签名是

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

如果满足RandomAccessIterator的要求,可以一次操作前进n个位置。对于较小的迭代器,我们必须在循环中推进 it。因此,实现可能会执行类似于以下内容的操作:

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

我不知道你在做什么的具体名称。这只是一个如何遵循 DRY 的示例原则。

如果 barAB 的实例作为参数,那么我将以不同的方式实现它。我没有让 bar 成为函数模板,然后提供特化,而是让重载解析为我完成这项工作。

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

但由于情况并非如此,提供明确的特化似乎是正确的方法。

关于c++ - 这是 "Tag Dispatching"吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23976795/

相关文章:

c++ - 错误 : cannot convert 'void (CApp::*)()' to 'void (*)()' for argument '1' to 'void Mix_HookMusicFinished(void (*)())'

c++ - 在指向成员的指针之间转换

c++ - 类(class)的私有(private)成员在我的类(class)实例化期间发生了变化,即使他们不应该

c++ - 为 UDF std::unordered_map 提供 ":"运算符?

c++ - 错误 : C2059: syntax error : '{'

c++ - 可以将两个连续的相同类型的数组视为一个吗?

c++ - 如何在类中包含模板成员?

c++ - 具有通用功能的专用模板类

arrays - C++11 段错误试图动态地将数组(<algorithm>)复制到向量中

android - 使用 c++static 的 NDK 编译错误