在C ++中标记调度示例

时间:2015-09-11 11:22:52

标签: c++ templates

我开始使用example available here并修改它以获取以下代码:

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

任何人都可以解释为什么这个特定(修改过的)示例会因分段错误而崩溃吗?如果我编译它,即使使用-Wall with g ++ 4.x,我也不会收到任何类型的警告。

4 个答案:

答案 0 :(得分:7)

我会将您的代码简化为一个简单的示例:

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

Example

答案 1 :(得分:1)

带签名

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

递归调用自己直到崩溃。

答案 2 :(得分:0)

在Valgrind下运行程序会显示由此行引起的堆栈溢出:

  work_dispatch(3.0);

执行此行:work_dispatch(typename traits<T>::tag());一遍又一遍(导致堆栈溢出)。

编辑:我认为您应该尝试使用以下修补程序:

#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. 执行调度提供值(我还将函数参数更改为T参考)
  2. 将值传递给从调度函数启动的模板化函数。

答案 3 :(得分:0)

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

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

并且您不会收到任何错误,因为&#34;替换失败不是错误&#34;。