有没有办法将函数模板作为另一个函数中的参数传递?

Is there a way to pass a function template, as an argument in another function?

提问人:Sam Moldenha 提问时间:7/28/2023 最后编辑:JeJoSam Moldenha 更新时间:7/28/2023 访问量:123

问:

对我来说,描述我所问的最好方式是一个简单的例子。

template<typename T>
void execute_example(T* begin, T* end) 
{
    T val = 10 * 0.8;
    while (begin != end) 
    {
        *begin = val;
        val *= 0.8;
        ++begin;
    }
}

using var_t = std::variant<float*, int*, double*>;

// I am just going to assume the type in input is *float to save lines
template<class UnaryOperator>
void my_function(UnaryOperator unary_op, var_t input, size_t size) 
{
    if (input.index() != 0)
        return;
    float* begin = std::get<0>(input);
    float* end = begin + size;
    unary_op<float>(begin, end);
}

int main() 
{
    float* vals = new float[](10);
    my_function(execute_example, vals, 10); // How can I pass execute_example here ??
    delete[] vals;
}

我基本上试图弄清楚如何做的是传递一个需要模板作为函数参数的函数。例如,如果我只是将模板参数设置为浮点,而不是模板参数,这将起作用:T

void execute_example(float* begin, float* end) 
{
    float val = 10 * 0.8;
    while (begin != end) {
        *begin = val;
        val *= 0.8;
        ++begin;
    }
}

using var_t = std::variant<float*, int*, double*>;

// I am just going to assume the type in input is *float to save lines
template<class UnaryOperator>
void my_function(UnaryOperator unary_op, var_t input, size_t size)
{
    if (input.index() != 0)
        return;
    float* begin = std::get<0>(input);
    float* end = begin + size;
    unary_op<float>(begin, end);
}

int main() 
{
    float* vals = new float[](10);
    my_function(execute_example, vals, 10); // works!!
    delete[] vals;
}

即使我更改为以下内容,它仍然不起作用。my_function

template<typename T>
void my_function(std::function<void(T*,T*)> unary_op, var_t input, size_t size)

有没有办法做到这一点?似乎应该有,因为以下内容也有效:

template<class UnaryOperator>
void my_function(UnaryOperator&& unary_op, var_t input, size_t size) 
{
    if (input.index() != 0)
        return;
    float* begin = std::get<0>(input);
    float* end = begin + size;
    std::forward<UnaryOperator>(unary_op)(begin, end);
}

int main()
{
    float* vals = new float[10];
    my_function([](auto* a, auto* b) {
        typedef typename std::remove_pointer<decltype(a)>::type value_t;
        value_t val = 10 * 0.8;
        while (a != b) {
            *a = val;
            val *= 0.8;
            ++a;
        }
    }, vals, 10);
    delete[] vals;
}

这将做同样的事情,我不必指定类型。

C++ 模板 lambda c++17 函数模板

评论

0赞 Eldinur the Kolibri 7/28/2023
这个 while 循环是如何终止的:?你不应该检查吗,因为你要把指针乘以一些奇数 0.8?可能是我的菜鸟观察,但我不明白这是如何工作的。while(begin != end)<begin
2赞 Sam Moldenha 7/28/2023
@EldinurtheKolibri 如果您运行它终止的代码,则该函数仅用作一个小示例,与我的问题并不真正相关。但是,显示的行递增指针,然后最终到达声明为 .这是大多数迭代器的工作方式,我只是碰巧使用了一个完全有效的指针。我建议您运行代码并查看它是否终止。您应该查看迭代器,并查看其上的文档遵循类似的格式。也可以观看一些关于指针算术:)的 youtube 视频++beginbeginendstd::for_each
0赞 ALX23z 7/28/2023
请参阅 en.cppreference.com/w/cpp/language/template_parameters 模板模板参数部分
0赞 n. m. could be an AI 7/28/2023
这个例子没有太大意义,因为你只使用变体的一个固定分支,你可以改用并制作一个非模板。float * inputmy_function
0赞 Sam Moldenha 7/28/2023
@n.m.willseey'allonReddit,这就是为什么我写评论的原因,我写这纯粹是为了可读性。不过,在实践中,我会将它用于变体中的所有不同类型。//I am just going to assume the type in input is *float to save lines

答:

4赞 JeJo 7/28/2023 #1

函数模板只是函数集的蓝图,调用方可以在某个时候建立该函数集。在它没有被实例化为聚集类型之前,你不能在那里脱掉任何东西,并将指向它函数的指针传递到任何地方。

此外,即使您也使用 ,问题也保持不变。它所需要的只是一个显式的模板参数。我建议以下,这也不需要.std::functionstd::variant

template<class UnaryOperator, typename T>
void my_function(UnaryOperator unary_op, T* input, size_t size) ,
{
    unary_op(input, input + size);
}

int main() 
{
    // use std::vector<float> or smart pointers here (If applicable)
    float* vals = new float[10]{}; 

    my_function(&execute_example<float>, vals, 10);

    delete[] vals;
}

或者将 作为通用 lambdaexecute_example

inline static constexpr auto execute_example = [](auto* begin, auto* end)
{
    // .....
};

template<class UnaryOperator, typename T>
void my_function(UnaryOperator unary_op, T* input, size_t size) 
{
    unary_op(input, input + size);
}

int main() 
{
    float* vals = new float[10] {};

    // Use std::vector<float> or smart pointers here (if applicable)
    my_function(execute_example, vals, 10);

    delete[] vals;
}

观看 godbolt.org 中的演示

评论

0赞 Remy Lebeau 7/28/2023
float* vals = new float[10]{}; ... delete[] vals;可以简化为仅在此示例中。float vals[10]{};
0赞 JeJo 7/28/2023
@RemyLebeau 更好的是使用 or .由于不清楚 OP 的实际用例是什么,我没有在答案中进一步简化这部分。std::array<type, 10>std::vector<type>
1赞 chrysante 7/28/2023 #2

您可以将函数模板包装在通用 lambda 中。即重写这一行

my_function(execute_example, vals, 10);

对此:

my_function([](auto* begin, auto* end) {
    execute_example(begin, end);
}, vals, 10);

调用运算符是一个模板,但 lambda 本身具有具体类型。这就是为什么你可以把它作为参数传递给另一个函数。operator()