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

huangapple go评论106阅读模式
英文:

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

问题

以下是您要翻译的代码部分:

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;
}

即使我将 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;
}

这将执行相同的操作,而且我不必指定一个类型。

英文:

The best way for me to describe what I am asking is a simple example.

template&lt;typename T&gt;
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&lt;float*, int*, double*&gt;;

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

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

What I am basically trying to figure out how to do is pass a function that needs a template as a function argument. For example, this would work, if instead of a template argument I just set T to float:

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&lt;float*, int*, double*&gt;;

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

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

Even if I changed my_function to the following, it still wouldn't work.

template&lt;typename T&gt;
void my_function(std::function&lt;void(T*,T*)&gt; unary_op, var_t input, size_t size)

Is there a way to do this? It seems like there should be because the following is also valid:

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

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

Which would do the same thing, and I would not have to specify a type.

答案1

得分: 4

函数模板只是一组函数的蓝图,调用者可以在某个时刻实例化它。除非它已经被实例化为具体的类型,否则无法访问其中的任何内容并将指针传递给它的函数。

此外,即使使用std::function,问题仍然存在,只是需要显式的模板参数。我建议以下方式,它也不需要std::variant

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

int main() 
{
    // 在这里使用std::vector<float>或智能指针(如果适用)
    float* vals = new float[10]{};

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

    delete[] vals;
}

或将execute_example定义为通用lambda函数:

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]{};

    // 在这里使用std::vector<float>或智能指针(如果适用)
    my_function(execute_example, vals, 10);

    delete[] vals;
}

在godbolt.org上查看演示

英文:

A function template is just a blueprint to the set of function, which caller may institute at some point. Until it hasn't been instantiated with congregate type, there you can not undress anything and pass the pointer to the function of it, to anywhere.

Additionally, the issue stays the same, even when you use the std::function as well. All it needs is an explicit template argument. I suggest the following, which also doesn't required the std::variant.

template&lt;class UnaryOperator, typename T&gt;
void my_function(UnaryOperator unary_op, T* input, size_t size) ,
{
    unary_op(input, input + size);
}

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

    my_function(&amp;execute_example&lt;float&gt;, vals, 10);

    delete[] vals;
}

Or make the execute_example as a generic lambda

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

template&lt;class UnaryOperator, typename T&gt;
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&lt;float&gt; or smart pointers here (if applicable)
    my_function(execute_example, vals, 10);

    delete[] vals;
}

See a demo in godbolt.org

答案2

得分: 1

你可以将函数模板包装在一个通用lambda中。也就是说,将这行代码重写为:

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

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

英文:

You can wrap the function template in a generic lambda. I.e. rewrite this line

my_function(execute_example, vals, 10);

to this:

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

The call operator operator() is a template, but the lambda itself has a concrete type. Thats why you can pass it as an argument to another function.

huangapple
  • 本文由 发表于 2023年7月28日 05:08:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76783418.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定