【问题标题】:Can I declare a template to only accept functions with homogeneous signature?我可以声明一个模板只接受具有同质签名的函数吗?
【发布时间】:2019-11-09 22:42:34
【问题描述】:

我有一组函数,每个函数都采用 T 类型的 N 参数,第二个是 X 类型的附加参数。

对于N=2T=intX=std::vector<int>,双份将是这样的:

void my_function2(int x1, int x2) {}
void my_function2(int x1, int x2, std::vector<int> other) {}

我正在尝试编写一个模板化的高阶函数,我将第一个函数传递给它。

这适用于N=2

template <typename R, typename T>
int my_hof(R(*param)(T, T)) { param(1,2); }

my_hof(&my_function2); // compiles

明确param 的签名很重要,否则模板实例化会因为“未解决的重载函数类型”而失败。重点是消除my_function2()的第二次重载。

我的问题是我想不出一种方法将其推广到N。我尝试使用可变参数模板:

template <typename R, typename ...X> 
struct make_signature { using type = R(*)(int, int); };
// Cheating a big on make_signature not to clutter the question
// But the idea would be to repeat the same type N times.

template <typename R, typename ...X>
int my_generalized_hof(typename make_signature<R, X...>::type param) {
    f(1,2); // cheating a bit on the call too 
}

my_generalized_hof(&my_function2); // does not compile

我猜编译器会因为param 的类型没有直接给出而感到困惑,它无法决定使用哪个重载来进行类型计算。 (“再次未解决的重载函数类型”)。我认为它也会拒绝进行类型计算,因为它无法推断出R 的类型。

我想不出生成签名的方法。

可以用 C++ 编写吗?

(请注意,我知道我可以通过在调用 my_generalized_hof() 时将 my_function2() 转换为正确的类型来选择重载,但我想避免这种情况)

【问题讨论】:

  • 如果我们事先不知道N 是什么,理论上我们必须通过无限数量的“Xs”才能找到正确的重载。如果f 过载,则无法从f 推断出N
  • 同意!我认为我正在寻找的是某种黑客攻击。就像某种“懒惰”地生成具有正确数量参数的my_generalized_hof 的方法。或者在模板参数推导之前某种方式去激活函数。理想情况下没有宏:)

标签: c++ variadic-templates template-meta-programming template-argument-deduction


【解决方案1】:

我提出以下make_signature

template <typename T, std::size_t>
using getType = T;

template <typename, typename, std::size_t N,
          typename = std::make_index_sequence<N>>
struct make_signature;

template <typename R, typename T, std::size_t N, std::size_t ... Is>
struct make_signature<R, T, N, std::index_sequence<Is...>>
 { using type = R(*)(getType<T, Is>...); };

但是有一个问题:当你写的时候

template <typename R, typename T, std::size_t N>
void my_generalized_hof (typename make_signature<R, T, N>::type param)
 {
   // do something with param
 }

make&lt;R, T, N&gt; 部分处于无推导上下文中(在 :: 之前),因此无法从参数中推导出 RTN

我的意思是……你不能打电话

 my_generalized_hof(&my_function2); 

您必须按如下方式显式显示模板参数

 // ...............VVVVVVVVVVVVVVV
 my_generalized_hof<void, int, 2u>(&my_function2); 

以下是完整的编译示例

#include <utility>
#include <vector>
#include <type_traits>

void my_function2(int x1, int x2) {}
void my_function2(int x1, int x2, std::vector<int> other) {}

template <typename T, std::size_t>
using getType = T;

template <typename, typename, std::size_t N,
          typename = std::make_index_sequence<N>>
struct make_signature;

template <typename R, typename T, std::size_t N, std::size_t ... Is>
struct make_signature<R, T, N, std::index_sequence<Is...>>
 { using type = R(*)(getType<T, Is>...); };

template <typename R, typename T, std::size_t N>
void my_generalized_hof (typename make_signature<R, T, N>::type param)
 {
   // do something with param
 }

int main ()
 {
   my_generalized_hof<void, int, 2u>(&my_function2); 
 }

【讨论】:

  • 这确实有效,但它相当于将my_function2 转换为您想要的签名。我想理想地避免这种情况(原因是我正在更改在许多地方调用的函数)。我想让我的模板足够聪明,可以自己选择同质重载。
  • @bkhantun - 在我看来,你想要一个太聪明的模板:选择一个给定签名的函数指针,并选择一个给定函数指针的签名。在我看来,这是一个先有鸡还是先有蛋的问题。但我很好奇,希望有人能找到解决办法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-17
  • 2012-09-10
相关资源
最近更新 更多