如果我没有在函数参数列表中使用tempate参数(type)->; 只作为返回类型,则没有扣减:
template <typename T>
T zero() { return 0; }
int main()
{
int x = zero();
}
给予:
a.cpp:15:18: error: no matching function for call to ‘zero()’
int x = zero();
^
a.cpp:11:3: note: candidate: ‘template<class T> T zero()’
T zero() { return 0; }
^~~~
a.cpp:11:3: note: template argument deduction/substitution failed:
a.cpp:15:18: note: couldn't deduce template parameter ‘T’
int x = zero();
编译的唯一方法是在尖括号中指定模板类型:
template <typename T>
T zero() { return 0; }
int main()
{
int x = zero<int>();
}
>
所以我的问题是,为什么G++可以从模板函数的参数列表推导出类型,而不能从返回类型(编译main
时也为编译器所知,所以知道类型)推导出来。
当模板函数在其参数列表中使用模板类型时,在尖括号中为模板函数提供类型是任意的(因为推论)? 因此,作为一个好的实践,我是否应该总是用花括号提供类型,不管函数是如何声明的?
第二个问题可读性不高。 用简单的话来说->; 我是否应该每次都使用foo
(提供类型),无论函数声明如何? 即使它可以被编译器推演,但我会提供类型无论如何好的实践?
通常,不可能根据函数的返回类型推导函数。 但是如果您使用自动类型转换C++特性,那么您就可以实现您所需要的:
template <typename T>
T zero() { return 1; }
template <>
float zero<float>() { return 3.0f; }
struct Zero
{
template<typename T>
operator T()
{
return zero<T>();
}
};
int main()
{
int x = Zero();
float y = Zero();
return x + y;
}
首先创建临时对象Zero(),在分配过程中使用转换运算符对Zero模板函数执行正确的专门化。
所以我的问题是,为什么g++可以从模板函数的参数列表中推导出类型
GCC遵循C++标准规定的规则。
我是否应该每次都使用foo(arg,。。。)(提供类型),无论函数声明?
那取决于你想要实现什么。 如果你想明确一点,那么就这么做吧。 这类似于调用C语言中的foo_t()
函数,该函数没有模板也没有重载。 但是,如果您希望代码是泛型的(例如,因为它是在模板本身中调用的,或者因为您希望在将来的类型更改时更容易更改),那么您最好避免显式地编写类型。
另一种选择是使用重载而不是模板。 您使用哪一个,再次,取决于您想要什么和您的用例。
最后,您还可以使用auto
:
auto zero() { return 0; }
话虽如此,但对于签名/接口,我认为最好的做法是处处使用显式类型,除非有理由不使用(例如它需要是模板):
int zero() { return 0; }
定义语言规则来满足这种情况并不是不可能的,但这将是非同小可的,完全没有意义的。
当决定其模板参数所需的所有信息都在该函数中时,该函数就不需要成为模板。 它应该只返回int
,句号。 如果您出于某种原因不想拼出返回类型,这就是auto
的用途:它将执行您所寻求的推演。
另一方面,如果您希望根据模板参数将0
转换为不同类型,那么这更有意义,并且您已经有了解决方案:提供模板参数(计算机如何猜到它?)。 在这个特定的示例中,您最好只是在调用站点进行转换,但您可能已经考虑了一些更复杂的逻辑。
至于是否应该始终显式地给出模板参数,即使它们是可推导的,我认为这在某种程度上是一个风格问题。 另一方面,它看起来很无意义,也很嘈杂,但另一方面,它可以自我文档化,并确保您正在调用您认为正在调用的专门化。 所以我认为这要视情况而定。