如何使用模板推断std :: function的参数类型?

熔化

我正在研究将类型的NxN矩阵旋转T90度的问题。本着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推导的模板类型传递

Yakk-亚当·内夫罗蒙特
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_clockwiselambda:

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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

从std :: function参数类型推导模板参数

从作为模板函数参数传递的std :: function推断返回值和参数类型?

如何让C ++从Lambda推断模板类型参数?

无法从lambda函数推断出模板参数std :: function

无法推断出模板参数(向量,std :: function)

std :: function无法推断模板实例中的重载类型

c ++模板参数类型推断

整体模板参数的类型推断

从函数参数推断模板类型

如何帮助模板类型推断

如何推断C ++ 11中的模板参数类型?

我可以在std :: function模板签名类型参数中使用命名参数吗?

如何使用可变参数模板使用std :: function

如何使用函数签名的typedef作为std :: function的类型参数?

从函数返回类型推断模板参数类型

推断非类型模板参数的类型

使用 auto 添加 const 的 std::function 参数类型的类型推导

如何使用带有模板参数的std :: function

可变参数模板,类型扣除和std :: function

使用std :: async时,C ++“无法推断出模板参数”

'候选模板被忽略:无法推断模板参数'与 std::set

如何正确声明以函数类型为参数的模板(如std :: function)

如何推断函数参数的类型?

从类定义中推断模板参数类型

从标记模板文字函数参数推断类型

如何推断模板中的数组类型?

模板如何推断 const 指针类型?

constexpr构造函数的参数类型'std :: function'不是文字类型

如何使用提供的参数推断函数的返回类型?