当前位置:  开发笔记 > 编程语言 > 正文

如果未实施除法运算符,则SFINAE回退

如何解决《如果未实施除法运算符,则SFINAE回退》经验,为你挑选了2个好方法。

我想编写一个函数,它在两个参数ab不同类型之间执行除法,a/b如果定义了除法运算符,则使用表达式,或者a * (1/b)如果没有这样的运算符则返回.

这是我的想法,但我不知道如何定义两个*/运算符时禁用第二个定义(或优先第一个定义):

template
auto smart_division(T a, U b) -> decltype (a/b) {
    return a/b;
}
template
auto smart_division(T a, U b) -> decltype (a * (U(1)/b)) {
    return a * (U(1)/b);
}

Piotr Skotni.. 20

最简单的技巧是依赖已经定义其优先级规则的重载决策.在下面的溶液中,用一个额外的参数0,0 -> int是优于0 -> char,因此,前者将是优选的一个如果不是由表达式SFINAE排除在外,而后者仍然可行的后备调用.

#include 

template 
auto smart_division_impl(T a, U b, int)
    -> decltype(a/b)
{
    return a/b;
}

template 
auto smart_division_impl(T a, U b, char)
    -> decltype(a * (U(1)/b))
{
    return a * (U(1)/b);
}

template 
auto smart_division(T&& a, U&& b)
    -> decltype(smart_division_impl(std::forward(a), std::forward(b), 0))
{
    return smart_division_impl(std::forward(a), std::forward(b), 0);
}

DEMO

如果你有更多的重载,你可以改为引入一个帮助器类型来优先考虑每个:

template  struct rank : rank {};
template <> struct rank<0> {};

template 
auto smart_division_impl(T a, U b, rank<2>) -> decltype(a/b) 
//                                 ~~~~~~^ highest priority
{
    return a/b;
}

template 
auto smart_division_impl(T a, U b, rank<1>) -> decltype(a * (U(1)/b))
//                                 ~~~~~~^ mid priority
{
    return a * (U(1)/b);
}

template 
int smart_division_impl(T a, U b, rank<0>)
//                                ~~~~~~^ lowest priority
{
    return 0;
}

template 
auto smart_division(T&& a, U&& b)
    -> decltype(smart_division_impl(std::forward(a), std::forward(b), rank<2>{}))
{
    return smart_division_impl(std::forward(a), std::forward(b), rank<2>{});
}

演示2

在这里再次rank<2> -> rank<2>优于rank<2> -> rank<1>反过来rank<2> -> rank<0>



1> Piotr Skotni..:

最简单的技巧是依赖已经定义其优先级规则的重载决策.在下面的溶液中,用一个额外的参数0,0 -> int是优于0 -> char,因此,前者将是优选的一个如果不是由表达式SFINAE排除在外,而后者仍然可行的后备调用.

#include 

template 
auto smart_division_impl(T a, U b, int)
    -> decltype(a/b)
{
    return a/b;
}

template 
auto smart_division_impl(T a, U b, char)
    -> decltype(a * (U(1)/b))
{
    return a * (U(1)/b);
}

template 
auto smart_division(T&& a, U&& b)
    -> decltype(smart_division_impl(std::forward(a), std::forward(b), 0))
{
    return smart_division_impl(std::forward(a), std::forward(b), 0);
}

DEMO

如果你有更多的重载,你可以改为引入一个帮助器类型来优先考虑每个:

template  struct rank : rank {};
template <> struct rank<0> {};

template 
auto smart_division_impl(T a, U b, rank<2>) -> decltype(a/b) 
//                                 ~~~~~~^ highest priority
{
    return a/b;
}

template 
auto smart_division_impl(T a, U b, rank<1>) -> decltype(a * (U(1)/b))
//                                 ~~~~~~^ mid priority
{
    return a * (U(1)/b);
}

template 
int smart_division_impl(T a, U b, rank<0>)
//                                ~~~~~~^ lowest priority
{
    return 0;
}

template 
auto smart_division(T&& a, U&& b)
    -> decltype(smart_division_impl(std::forward(a), std::forward(b), rank<2>{}))
{
    return smart_division_impl(std::forward(a), std::forward(b), rank<2>{});
}

演示2

在这里再次rank<2> -> rank<2>优于rank<2> -> rank<1>反过来rank<2> -> rank<0>



2> RiaD..:

如果两者都可以编译,你应该选择其中一个选项.例如:

#include 

template
auto helper(T a, U b, int) -> decltype (a/b) {
    std::cout << "first";
    return a/b;
}

template
auto helper(T a, U b, ...) -> decltype (a * (U(1)/b)) {
    std::cout << "second";
    return a * (U(1)/b);
}

template
auto smart_division(T a, U b) -> decltype (helper(a, b)) {
    return helper(a, b, 0);
}


struct Test {
    explicit Test(int) {}
};
int operator / (Test a, Test b) {
return 1;
}

int main() {
    std::cout << smart_division(1.0, 2.0);
    Test t{5};
    std::cout << smart_division(1, t);
    return 0;
}

这里如果没有可用的除法,则第二个函数是唯一可用的函数.如果划分可用,则有2个功能:

helper(T, U, int)并且helper(T, U, ...)第一个更适合呼叫helper(t, u, 1)

DEMO

请注意,您可能希望在smart_division中使用完美转发,为了清楚起见,我跳过了它

推荐阅读
重庆制造漫画社
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有