问题描述
我用一个额外的模板参数创建了一个简单的舍入模板函数,该参数定义了返回前需要将舍入值转换为类型的类型.
I created a simple round template function with an extra template argument that defines the type the rounded value needs to be casted to before returning.
template <typename T, typename U>
T round(U val) {
T result;
if (val >= 0)
result = (T)(floor(val + (U)(.5)));
else
result = (T)(ceil( val - (U)(.5)));
return result;
}
int a = round<int>(5.5); // = 6
// no compiler warnings
但是我也希望保留额外的模板参数,这样您就不必插入已经添加为参数的类型.
But I also want the possibility to leave the extra template argument so that you don't have to insert the type you already added as an argument.
template <typename T>
T round(T val) {
return round<T>(val);
}
double b = round(5.5) // = 6.0
// C2668
但是,现在编译器抱怨:
However, now the compiler complains:
我认为编译器将始终选择最具体的模板,该模板应该是最后一个.为什么不是这种情况,并且有任何变通办法(不是专门针对此回合函数的)?
I thought the compiler would always choose the most specific template, which should be the last one. Why is this not the case and are there any workarounds (not specifically for this round function)?
模糊调用不是指向round(5.5)
,而是指向return round<T>(val);
.因此,此问题的答案是将重载函数的返回值重写为
The ambiguous call wasn't pointing to round(5.5)
but rather to return round<T>(val);
. The answer to this question was thus to rewrite the return value for the overloaded function to
return round<T,T>(val);
解决了这个问题.
推荐答案
由于在模板参数推导过程中未推导返回类型,因此您将收到错误消息.而是从推导的函数参数中替换它们.因为两个重载都推导了相同的参数,所以重载重排是模棱两可的,这会导致编译器错误.
You are getting an error because return types are not deduced during template argument deduction. Instead they are substituted from the deduced function arguments. Because both overloads have the same arguments deduced, overload resoution is ambiguous which gives a compiler error.
在C ++ 11中,您可以为功能模板定义默认模板参数.如果您添加了一个额外的默认函数参数,该参数等于默认返回值,除非您明确传递默认返回值,否则始终将参数类型作为返回类型:
In C++11 you can define a default template parameter for function templates. If you add an extra default function parameter equal to the default return value, you will always get the argument type as return type, unless you explicitly pass a default return value:
#include <iostream>
#include <cmath>
#include <type_traits>
template <typename T, typename Ret = T>
Ret xround(T val, Ret ret = Ret()) {
return static_cast<Ret>(
(val >= 0) ?
floor(val + (T)(.5)) :
ceil( val - (T)(.5))
);
}
int main()
{
auto a = xround(5.5, int()); // = 6
static_assert(std::is_same<decltype(a), int>::value, "");
std::cout << a << "\n";
auto b = xround(5.5); // = 6.0
static_assert(std::is_same<decltype(b), double>::value, "");
std::cout << b << "\n";
}
请注意,我使用三元运算符而不是您的if-else
,并且我将函数重命名为xround
,因为在C ++ 11中,<cmath>
中已经有一个round
(当然,也可以使用).
Note that I used the ternary operator instead of your if-else
, and that I renamed the function to xround
because in C++11 there already is a round
inside <cmath>
(which of course you could also use).
注意:该临时变量类似于标记分发:它完全用于确定返回类型,实际的临时变量应由编译器优化.
Note: the temporary is similar to tag dispatching: it is entirely used to determine the return type and the actual temporary should be optimized away by the compiler.
这篇关于通过重载实现部分模板专业化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!