为什么编译器不能从函数参数中推导出我的模板值?

时间:2015-07-06 15:39:17

标签: c++ templates non-type argument-deduction

以下内容无法编译:

enum E {A,B,C};
template<E m> 
void foo(E m) {}

int main() {
    foo(A);
    return 0;
}

我得到的错误是:

  • 'E m'的声明:void foo(E m){}:阴影模板parm'E m'
  • 错误:没有匹配函数来调用'foo(E)': FOO(A);
  • 候选人是:template void foo(E):void foo(E m){}
  • 模板参数扣除/替换失败:无法推断模板参数'm':foo(A);

我不明白这里到底出了什么问题。为什么编译器不能从函数参数中推导出模板参数?

我需要做些什么来完成这项工作?

3 个答案:

答案 0 :(得分:5)

如果需要运行时参数,请使用:

void foo(E m) {}

其类型m的值E。 (注意:不需要template<E m>

如果需要编译时参数,请使用:

template<E m> 
void foo() {}

并致电:

foo<A>();

或者,如果您希望foo适用于所有枚举类型:

template<typename E> 
void foo(E m) {}

可能用

检查枚举
static_assert(std::is_enum<E>::value, "E is not an enumeration");

在函数体中。 (如果需要,您还可以使用SFINAE从过载集中删除foo,询问您是否需要帮助)

更新:解释原始代码及其错误:

template<E m> void foo(E m) {}
//       ^^^ (1)       ^^^ (2)

(1)是m类型的编译时参数E,(2)是运行时参数,名为m,也是类型为E。由于它具有相同的名称,因此第二个参数隐藏第一个参数。在函数中使用名称m将只访问第二个参数,而您无法访问第一个参数。现在考虑:

template<E m1> void foo(E m2) {}

现在您可以使用不同的名称访问参数,即m1m2。如果你这样调用函数:

foo<A>(B);

然后m1Am2B。并且两者都具有相同的固定类型E。它们是独立参数,运行时参数的值不会用于编译时参数。

根据您需要的类型或参数(编译时或运行时),您只需省略您不需要的那种,并最终获得上述实现之一。

我并不是100%清楚你真正的问题在哪里,这对初学者来说并不典型,因为很难描述你不了解的问题,但要确保你从理解编译时和运行时参数之间的区别以及如何使用它们。

答案 1 :(得分:2)

我想你想写:

enum E {A,B,C};
template<typename T> 
void foo(T m) {}

int main() {
    foo(A);
    return 0;
}

答案 2 :(得分:0)

我终于明白了为什么这不能编译。虽然在我的特定情况下,函数参数是编译时常量(枚举成员),但通常函数参数是运行时相关的。模板值必须是编译时常量,因此模板值推导不允许使用函数参数值。如果强制执行此操作的机制是名称隐藏,那么我认为这是偶然的。 结论是,虽然模板化函数类型可以从函数参数类型推导出来,但模板值不可推导。

相关问题