C++中的标记调度示例

Tag dispatching example in C++

本文关键字:调度 C++      更新时间:2023-10-16

我开始使用这里提供的示例,并对其进行了修改以获得以下代码:

#include <iostream>
struct slow_tag {}; 
struct fast_tag {};
template <typename T>
struct traits
{
  typedef slow_tag tag;
};
template <>
struct traits<int>
{
  typedef fast_tag tag;
};
template <typename T>
void work_dispatch(const slow_tag)
{
  std::cout << "Slow function" << std::endl;
}
template <typename T>
void work_dispatch(const fast_tag)
{
  std::cout << "Fast function" << std::endl;
}
template <typename T>
void work_dispatch(const T)
{
  work_dispatch(typename traits<T>::tag());
}
int main()
{
  std::cout << "Starting my program" << std::endl;
  work_dispatch(3.0);
  work_dispatch(3);
}

有人能解释我为什么这个特殊的(修改的(例子会因为分段错误而崩溃吗?如果我编译它,即使在使用带有g++4.x的-Wall时,我也不会得到任何类型的警告。

我将把您的代码简化为一个简单的例子:

#include <iostream>
template <typename T>
void work_dispatch(double)
{
  std::cout << "Slow function" << std::endl;
}
int main()
{
  work_dispatch(3.0);
}

编译错误:

main.cpp:11:3: error: no matching function for call to 'work_dispatch'
  work_dispatch(3.0);
  ^~~~~~~~~~~~~
main.cpp:4:6: note: candidate template ignored: couldn't infer template argument 'T'
void work_dispatch(double)
     ^
1 error generated.

换句话说,你不能称这个模板为

template <typename T>
void work_dispatch(double)
{
  std::cout << "Slow function" << std::endl;
}

带有

work_dispatch(3.0);

由于无法推导类型T,也无法显式传递它。因此,由于无限递归导致堆栈溢出:

template <typename T>
void work_dispatch(const T) <----------------|
{                                            | This ends up calling itself
  work_dispatch(typename traits<T>::tag()); -|
}

要修复您的代码,最简单的解决方案是提供自己类型的

template <typename T>
void work_dispatch(const T)
{
  work_dispatch<T>(typename traits<T>::tag());
}

示例

带有签名

template <typename T>
void work_dispatch(const slow_tag);

T无法推导,因此您必须在调用中提供它

template <typename T>
void work_dispatch(const T)
{
    work_dispatch<T>(typename traits<T>::tag());
}

如目前

template <typename T>
void work_dispatch(const T)
{
    work_dispatch(typename traits<T>::tag());
}

递归地调用自己,直到崩溃。

template <typename T>
void work_dispatch(const slow_tag)  
{
    std::cout << "Slow function" << std::endl;
}

编译器无法确定此函数中的T应该是什么,因此在重载解析中不考虑它。

你不会得到任何错误,因为"替换失败不是错误"。

在Valgrind下运行程序表明,由于以下行导致堆栈溢出:

  work_dispatch(3.0);

它一次又一次地执行这一行:CCD_ 4(导致堆栈溢出(。

编辑:我认为您在这里尝试做的事情应该可以通过以下修复:

#include <iostream>
struct slow_tag {};
struct fast_tag {};
template <typename T>
struct traits {
    typedef slow_tag tag;
};
template <>
struct traits<int> {
    typedef fast_tag tag;
};
template <typename T>
void work_dispatch(const T& val, const slow_tag& st) {
    std::cout << "Slow function" << std::endl;
}
template <typename T>
void work_dispatch(const T& val, const fast_tag& ft) {
    std::cout << "Fast function" << std::endl;
}
template <typename T>
void work_dispatch(const T& val) {
    work_dispatch(val, typename traits<T>::tag());
}
int main() {
    std::cout << "Starting my program" << std::endl;
    work_dispatch(3.0);
    work_dispatch(3);
}

也就是说,你应该:

  1. 做dispatch提供值(我还将函数参数更改为T引用(
  2. 将值传递给从分派函数启动的两个模板化函数