我想编写一个函数,它在两个参数a
和b
不同类型之间执行除法,a/b
如果定义了除法运算符,则使用表达式,或者a * (1/b)
如果没有这样的运算符则返回.
这是我的想法,但我不知道如何定义两个*
和/
运算符时禁用第二个定义(或优先第一个定义):
templateauto 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排除在外,而后者仍然可行的后备调用.
#includetemplate 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
如果你有更多的重载,你可以改为引入一个帮助器类型来优先考虑每个:
templatestruct 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>
最简单的技巧是依赖已经定义其优先级规则的重载决策.在下面的溶液中,用一个额外的参数0
,0 -> int
是优于0 -> char
,因此,前者将是优选的一个如果不是由表达式SFINAE排除在外,而后者仍然可行的后备调用.
#includetemplate 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
如果你有更多的重载,你可以改为引入一个帮助器类型来优先考虑每个:
templatestruct 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>
如果两者都可以编译,你应该选择其中一个选项.例如:
#includetemplate 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中使用完美转发,为了清楚起见,我跳过了它