pqn*_*net 17 c++ templates sfinae c++11
我想编写一个函数,它在两个参数a
和b
不同类型之间执行除法,a/b
如果定义了除法运算符,则使用表达式,或者a * (1/b)
如果没有这样的运算符则返回.
这是我的想法,但我不知道如何定义两个*
和/
运算符时禁用第二个定义(或优先第一个定义):
template<typename T, typename U>
auto smart_division(T a, U b) -> decltype (a/b) {
return a/b;
}
template<typename T, typename U>
auto smart_division(T a, U b) -> decltype (a * (U(1)/b)) {
return a * (U(1)/b);
}
Run Code Online (Sandbox Code Playgroud)
Pio*_*cki 20
最简单的技巧是依赖已经定义其优先级规则的重载决策.在下面的溶液中,用一个额外的参数0
,0 -> int
是优于0 -> char
,因此,前者将是优选的一个如果不是由表达式SFINAE排除在外,而后者仍然可行的后备调用.
#include <utility>
template <typename T, typename U>
auto smart_division_impl(T a, U b, int)
-> decltype(a/b)
{
return a/b;
}
template <typename T, typename U>
auto smart_division_impl(T a, U b, char)
-> decltype(a * (U(1)/b))
{
return a * (U(1)/b);
}
template <typename T, typename U>
auto smart_division(T&& a, U&& b)
-> decltype(smart_division_impl(std::forward<T>(a), std::forward<U>(b), 0))
{
return smart_division_impl(std::forward<T>(a), std::forward<U>(b), 0);
}
Run Code Online (Sandbox Code Playgroud)
如果你有更多的重载,你可以改为引入一个帮助器类型来优先考虑每个:
template <int I> struct rank : rank<I-1> {};
template <> struct rank<0> {};
template <typename T, typename U>
auto smart_division_impl(T a, U b, rank<2>) -> decltype(a/b)
// ~~~~~~^ highest priority
{
return a/b;
}
template <typename T, typename U>
auto smart_division_impl(T a, U b, rank<1>) -> decltype(a * (U(1)/b))
// ~~~~~~^ mid priority
{
return a * (U(1)/b);
}
template <typename T, typename U>
int smart_division_impl(T a, U b, rank<0>)
// ~~~~~~^ lowest priority
{
return 0;
}
template <typename T, typename U>
auto smart_division(T&& a, U&& b)
-> decltype(smart_division_impl(std::forward<T>(a), std::forward<U>(b), rank<2>{}))
{
return smart_division_impl(std::forward<T>(a), std::forward<U>(b), rank<2>{});
}
Run Code Online (Sandbox Code Playgroud)
在这里再次rank<2> -> rank<2>
优于rank<2> -> rank<1>
反过来rank<2> -> rank<0>
如果两者都可以编译,你应该选择其中一个选项.例如:
#include <iostream>
template<typename T, typename U>
auto helper(T a, U b, int) -> decltype (a/b) {
std::cout << "first";
return a/b;
}
template<typename T, typename U>
auto helper(T a, U b, ...) -> decltype (a * (U(1)/b)) {
std::cout << "second";
return a * (U(1)/b);
}
template<typename T, typename U>
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;
}
Run Code Online (Sandbox Code Playgroud)
这里如果没有可用的除法,则第二个函数是唯一可用的函数.如果划分可用,则有2个功能:
helper(T, U, int)
并且helper(T, U, ...)
第一个更适合呼叫helper(t, u, 1)
请注意,您可能希望在smart_division中使用完美转发,为了清楚起见,我跳过了它