通过重载实现部分模板专业化 [英] Partial template specialization by overloading

查看:98
本文介绍了通过重载实现部分模板专业化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用一个额外的模板参数创建了一个简单的舍入模板函数,该参数定义了返回前需要将舍入值转换为类型的类型.

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:

错误C2668:对重载函数的模棱两可

error C2668: ambiguous call to overloaded function

我认为编译器将始终选择最具体的模板,该模板应该是最后一个.为什么不是这种情况,并且有任何变通办法(不是专门针对此回合函数的)?

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);

解决了这个问题.

感谢 galop1n 对于我的其他问题的答案

推荐答案

由于在模板参数推导过程中未推导返回类型,因此您将收到错误消息.而是从推导的函数参数中替换它们.因为两个重载都推导了相同的参数,所以重载重排是模棱两可的,这会导致编译器错误.

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.

这篇关于通过重载实现部分模板专业化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆