简体   繁体   English

通过重载部分模板专业化

[英]Partial template specialization by overloading

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: 但是,现在编译器抱怨:

error C2668: ambiguous call to overloaded function 错误C2668:对重载函数的模糊调用

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)? 为什么不是这种情况,是否有任何变通方法(不是专门针对此轮次函数)?


The ambiguous call wasn't pointing to round(5.5) but rather to return round<T>(val); 模糊的调用并没有指向round(5.5)而是指向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);

which solves the problem. 这解决了这个问题。

Thanks to galop1n for the answer to my other question . 感谢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. 因为两个重载具有相同的参数推导,所以过载资源是不明确的,这给出了编译器错误。

In C++11 you can define a default template parameter for function templates. 在C ++ 11中,您可以为函数模板定义默认模板参数。 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";
}   

Live Example 实例

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

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. 注意 :临时类似于标签分派:它完全用于确定返回类型,实际的临时应由编译器优化。

Your issue is not template specialization, but an overload ambiguity. 您的问题不是模板专业化,而是过载模糊。

This is similar: 这是类似的:

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

Having a template where U has T as default parameter will not do better: 有一个模板,其中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
}

And a partial specialization is not allowed: 并且不允许部分专业化:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM