我正在研究将类型的NxN矩阵旋转T
90度的问题。本着DRY的精神,我希望旋转函数的函数签名看起来像这样:
template <typename T, std::size_t N>
void rotate_90(Matrix<T, N>& m, std::function<void(T&, T&, T&, T&)> swap_direction);
这将允许我简单地通过传递不同的来顺时针和逆时针交换相同的功能std::function<void(T&, T&, T&, T&)>
。
我目前有以下代码:
#include <iostream>
#include <array>
#include <functional>
template <typename T, std::size_t N>
using Matrix = std::array<std::array<T, N>, N>;
template <typename T>
void four_way_swap_clockwise(T& top_left, T& top_right, T& bottom_left, T& bottom_right) {
T temp = top_left;
top_left = top_right;
top_right = bottom_right;
bottom_right = bottom_left;
bottom_left = temp;
}
template <typename T, std::size_t N>
void rotate_90(Matrix<T, N>& m, std::function<void(T&, T&, T&, T&)> swap_direction) {
for(std::size_t i = 0; i < N/2; ++i) {
for(std::size_t j = 0; j < (N+1)/2; ++j) {
swap_direction(
m[i][j],
m[N-j-1][i],
m[j][N-i-1],
m[N-i-1][N-j-1]
);
}
}
}
int main() {
constexpr std::size_t N = 5;
Matrix<int, N> m {{
{{1,2,3,4,5}},
{{6,7,8,9,10}},
{{11,12,13,14,15}},
{{16,17,18,19,20}},
{{21,22,23,24,25}}
}};
std::function<void(int&, int&, int&, int&)> swap_clockwise(four_way_swap_clockwise);
rotate_90(m, swap_clockwise);
}
当前无法编译,失败,并显示以下错误:
error: no matching function for call to 'std::function<void(int&, int&, int&, int&)>::function(<unresolved overloaded function type>)'
std::function<void(int&, int&, int&, int&)> swap_clockwise(four_way_swap_clockwise);
但是,即使它确实进行了编译,也无法实现模板编程来指定交换函数的参数类型(即在的定义中std::function<void(int&, int&, int&, int&)> swap_clockwise(four_way_swap_clockwise);
)的目的。
如何通过std::function
推导的模板类型传递?
template<class T> struct tag_t{using type=T;};
template<class T> using block_deduction=typename tag_t<T>::type;
此构造阻止C ++尝试从函数参数中推断出模板参数。
template <typename T, std::size_t N>
void rotate_90(Matrix<T, N>& m, block_deduction<std::function<void(T&, T&, T&, T&)>> swap_direction) {
现在,总是从第一个参数的类型推导出第二个参数的类型!
下一个问题是std::function
不会消除重载的函数名称的歧义。重载的函数名称不是C ++值,而是在正确的上下文中找到值的一组名称。std::function
建设不是这些背景之一。
我们可以扩展std::function
一个像这样的附加构造函数:
template<class Sig, class F=std::function<Sig>>
struct my_func:F {
using F::F;
using F::operator=;
my_func( Sig* ptr ):F(ptr) {}
my_func& operator=( Sig* ptr ) {
F::operator=(ptr);
return *this;
}
my_func()=default;
my_func(my_func&&)=default;
my_func(my_func const&)=default;
my_func& operator=(my_func&&)=default;
my_func& operator=(my_func const&)=default;
};
现场例子。
另一种方法是将重载集合包装到lambda中:
auto overloads = [](auto&&...args){ return four_way_swap_clockwise(decltype(args)(args)...); };
然后将传递overloads
给您的函数。这个lambda一次代表了所有重载four_way_swap_clockwise
。
我们也可以通过手动消除歧义four_way_swap_clockwise<int>
。
这两个仍然需要block_deduction
上面的技术。
要考虑的替代方法是:
template <typename T, std::size_t N, class F>
void rotate_90(Matrix<T, N>& m, F&& swap_direction)
让我们swap_direction
完全自由,让算法中发生任何故障。这也会略微提高性能。您仍然必须four_way_swap_clockwise
使用<int>
lambda-wrapper技术消除歧义。
另一种方法是自己制作for_way_swap_clockwise
lambda:
auto four_way_swap_clockwise = [](auto& top_left, auto& top_right, auto& bottom_left, auto& bottom_right) {
auto temp = top_left;
top_left = top_right;
top_right = bottom_right;
bottom_right = bottom_left;
bottom_left = temp;
};
现在它是一个带有模板operator()
重载的对象。这样可以block_deduction
解决您的问题。
简而言之,有很多方法可以解决您的问题。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句