2

以下不会编译:

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

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

我得到的错误是:

  • 'E m' 的声明:void foo(E m) {}:阴影模板参数 'E m'
  • 错误:没有匹配函数调用“foo(E)”:foo(A);
  • 候选者是:模板 void foo(E) : void foo(E m) {}
  • 模板参数推导/替换失败:无法推导模板参数'm':foo(A);

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

我需要做什么才能完成这项工作?

4

3 回答 3

6

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

void foo(E m) {}

其值为mtype 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");

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


更新:解释您的原始代码及其有什么问题:

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

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

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

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

foo<A>(B);

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

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

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

于 2015-07-06T15:45:08.513 回答
2

我猜你想写:

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

int main() {
    foo(A);
    return 0;
}
于 2015-07-06T15:46:28.973 回答
0

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

于 2015-07-08T11:17:04.017 回答