模板化函数模板参数的返回类型

时间:2019-07-05 20:43:53

标签: c++ c++14

在传递给各种签名的函数之前,我正在尝试编写一些用于转换参数类型的样板。最简单的示例是采用一个需要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)的新专业化名称。

不过,仅对返回类型进行模板化会更方便。我引入其他模板参数的所有尝试均以失败告终。这可能吗?如果可以,怎么办?还是有更好的方法?

3 个答案:

答案 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);

看起来很丑,但是行得通。