在传递给各种签名的函数之前,我正在尝试编写一些用于转换参数类型的样板。最简单的示例是采用一个需要int*
的函数,并将其包装起来以创建一个采用std::vector
的函数,如以下示例所示。
#include <vector>
#include <iostream>
using namespace std;
template <void (*F)(int*, size_t)>
void tfunc_api(vector<int>& a)
{
return F(&(a[0]), a.size());
}
void reset(int* a, size_t n)
{
for (size_t i=0; i < n; i++)
{
a[i] = 0;
}
}
int main(void)
{
vector<int> foo = {1,2,3,4};
tfunc_api<reset>(foo);
for (auto e: foo)
cout << e << endl;
}
我正在使用函数模板参数,因为这是处理不同签名的最简单方法,例如void (*F)(int*, int*, size_t)
。
如果我现在想为具有不同返回类型的类似函数创建包装,例如
int sum(int* a, size_t n)
{
int sum = 0;
for (size_t i=0; i < n; i++)
{
sum += a[i];
}
return sum;
}
然后我可以为模板参数tfunc_api
写一个int (*F)(int*, size_t)
的新专业化名称。
不过,仅对返回类型进行模板化会更方便。我引入其他模板参数的所有尝试均以失败告终。这可能吗?如果可以,怎么办?还是有更好的方法?
答案 0 :(得分:4)
在C ++ 17中,超级简单的解决方案是auto
:
template <auto (*F)(int*, size_t)>
auto tfunc_api(vector<int>& a)
或更通用:
template <auto F>
auto tfunc_api(vector<int>& a)
更通用的方法对于不限于函数指针很有用,并且可以与其他可调用对象一起使用,例如捕获lambda。如果签名错误,则错误消息可能不太明显。
在C ++ 14中,我将可调用对象作为常规参数而不是模板参数传递:
template <class Fun>
auto tfunc_api(vector<int>& a, Fun F)
// call
tfunc_api(foo, sum);
答案 1 :(得分:2)
您可以使用Lambda而不是模板化函数来在C ++ 14非详细说明中做到这一点:
auto tfunc_api = [] (auto F, vector<int>& a)
{
return F(&(a[0]), a.size());
};
void reset(int* a, size_t n)
{
for (size_t i=0; i < n; i++)
{
a[i] = 0;
}
}
int sum(int* a, size_t n)
{
int sum = 0;
for (size_t i=0; i < n; i++)
{
sum += a[i];
}
return sum;
}
int main(void)
{
vector<int> foo = {1,2,3,4};
cout << tfunc_api(sum, foo) << endl;
tfunc_api(reset, foo);
for (auto e: foo)
cout << e << endl;
}
答案 2 :(得分:0)
在C ++ 14中,将F
用作模板参数的唯一方法似乎是引入类型模板参数,然后使用decltype
:
template<class T, T F>
auto tfunc_api(std::vector<int>& a)
{
return F(&a[0], a.size());
}
std::cout << tfunc_api<decltype(sum), sum>(foo);
看起来很丑,但是行得通。