0

我创建了一个简单的圆形模板函数,其中包含一个额外的模板参数,该参数定义了在返回之前需要将舍入值转换为的类型。

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

但我也希望有可能留下额外的模板参数,这样您就不必插入已经添加为参数的类型。

template <typename T>
T round(T val) {
    return round<T>(val);
}

double b = round(5.5) // = 6.0
// C2668

但是,现在编译器抱怨:

错误 C2668:对重载函数的不明确调用

我认为编译器总是会选择最具体的模板,应该是最后一个。为什么不是这种情况,是否有任何解决方法(不是专门针对此轮函数)?


模棱两可的电话不是指向,round(5.5)而是指向return round<T>(val);. 因此,这个问题的答案是将重载函数的返回值重写为

return round<T,T>(val);

这解决了这个问题。

感谢galop1n回答我的另一个问题

4

2 回答 2

2

您收到错误消息,因为在模板参数推导期间未推导出返回类型。相反,它们是从推导的函数参数中替换的。因为两个重载都推导出了相同的参数,所以重载结果是模棱两可的,这会导致编译器错误。

在 C++11 中,您可以为函数模板定义默认模板参数。如果添加一个等于默认返回值的额外默认函数参数,您将始终将参数类型作为返回类型,除非您显式传递默认返回值:

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

现场示例

请注意,我使用了三元运算符而不是 your if-else,并且我将函数重命名为,xround因为在 C++11 中已经有一个roundinside <cmath>(当然你也可以使用它)。

注意:临时值类似于标签调度:它完全用于确定返回类型,实际的临时值应该由编译器优化掉。

于 2014-02-11T12:26:24.163 回答
0

您的问题不是模板专业化,而是过载歧义。

这是类似的:

int fn(int) { return 0; }
// error: new declaration ‘double fn(int)’
// error: ambiguates old declaration ‘int fn(int)’
double fn(int) { return 0; }

拥有一个 U 具有 T 作为默认参数的模板不会做得更好:

template <typename T, typename U = T>
T fn(U val) {
    return T();
}

int main() {
    // error: no matching function for call to ‘fn(double)’
    // note: template argument deduction/substitution failed:
    double d = fn(1.5); // fn<double>(1.5) will work
}

并且不允许部分专业化:

template <typename T, typename U>
T fn(U val) {
    return T();
}

// error: function template partial specialization ‘fn<T, T>’ is not allowed
template <typename T>
T fn<T, T>(T val) {
    return T();
}
于 2014-02-11T03:35:44.433 回答