Can I generalize this set of functions into one that takes a variable length argument list (e.g. by using a parameter pack)

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

Can I generalize this set of functions into one that takes a variable length argument list (e.g. by using a parameter pack)

问题

I'll provide the translated code parts for you:

我想知道是否有一种方法可以将这组函数泛化为一个接受任意数量的参数的函数。这里不需要Var和LetN的具体细节(这是一些表达式模板构建代码。LetN使用参数表达式创建一个本地词法环境,以及包装在Var表达式中的参数的索引) 我不知道如何编写一个表达式,将索引序列与参数输出类型的实例一起组合成Var的实例

template <typename Fun, typename A>
auto let(Fun fun, A a) {
	auto var0 = Var<0, get_out_type_t<A>>();
	return LetN(fun(var0), a);
}

template <typename Fun, typename A, typename B>
auto let(Fun fun, A a, B b) {
	auto var0 = Var<0, get_out_type_t<A>>();
	auto var1 = Var<1, get_out_type_t<B>>();
	return LetN(fun(var0, var1), a, b);
}

template <typename Fun, typename A, typename B, typename C>
auto let(Fun fun, A a, B b, C c) {
	auto var0 = Var<0, get_out_type_t<A>>();
	auto var1 = Var<1, get_out_type_t<B>>();
	auto var2 = Var<2, get_out_type_t<C>>();
	return LetN(fun(var0, var1, var2), a, b, c);
}
// 等等.. 其他参数个数的情况。

这是你的失败尝试的翻译:

template <typename Fun, typename... Args>
auto let2(Fun fun, Args... args) {
	using ArgsTuple = std::tuple<Args...>;
	auto g = [&](auto... indices){
		return std::make_tuple(Var<indices, typename std::tuple_element<indices, ArgsTuple>::OutType>()...);
	};
	auto vars = std::apply(g, std::index_sequence_for<Args...>());
	return LetN(fun(vars), args...);
}

对于你提到的编译错误,我无法提供具体解决方案,因为需要查看完整的代码和上下文来理解问题的根本原因。但这段代码的目的是尝试将参数包的索引序列与参数类型的Var实例组合起来。可能需要检查标头文件和库的包含,确保索引序列的使用正确。

关于是否应该这样做,是否会增加编译时间,这取决于具体情况。参数包的使用可能会导致编译时间增加,因为编译器需要处理更多的元编程操作。你需要进行性能测试以确定是否值得将这个变化引入代码中,还需要考虑代码的可维护性和清晰度。

英文:

I want to know if there is a way to generalize this set of functions into one that takes an arbitrary number of arguments. The specifics of Var and LetN shouldn't be needed here. (This is from some expression template building code. LetN creates a local lexical environment using the argument expressions, and the indices of the arguments wrapped in Var expressions.) The thing I don't know how to do is write an expression that zips an index sequence with the argument output types into instances of Var.

template &lt;typename Fun, typename A&gt;
auto let(Fun fun, A a) {
	auto var0 = Var&lt;0, get_out_type_t&lt;A&gt;&gt;();
	return LetN(fun(var0), a);
}

template &lt;typename Fun, typename A, typename B&gt;
auto let(Fun fun, A a, B b) {
	auto var0 = Var&lt;0, get_out_type_t&lt;A&gt;&gt;();
	auto var1 = Var&lt;1, get_out_type_t&lt;B&gt;&gt;();
	return LetN(fun(var0, var1), a, b);
}

template &lt;typename Fun, typename A, typename B, typename C&gt;
auto let(Fun fun, A a, B b, C c) {
	auto var0 = Var&lt;0, get_out_type_t&lt;A&gt;&gt;();
	auto var1 = Var&lt;1, get_out_type_t&lt;B&gt;&gt;();
	auto var2 = Var&lt;2, get_out_type_t&lt;C&gt;&gt;();
	return LetN(fun(var0, var1, var2), a, b, c);
}
// etc.. for other arities.

Here is my failed attempt:

template &lt;typename Fun, typename... Args&gt;
auto let2(Fun fun, Args... args) {
	using ArgsTuple = std::tuple&lt;Args...&gt;;
	auto g = [&amp;](auto... indices){
		return std::make_tuple(Var&lt;indices, typename std::tuple_element&lt;indices, ArgsTuple&gt;::OutType&gt;()...);
	};
	auto vars = std::apply(g, std::index_sequence_for&lt;Args...&gt;());
	return LetN(fun(vars), args...);
}

My attempt generates some compile errors regarding the integer_sequence that I don't really understand.

[...]/usr/include/c++/v1/tuple:1528:52: error: implicit instantiation of undefined template &#39;std::tuple_size&lt;std::integer_sequence&lt;unsigned long, 0, 1&gt;&gt;&#39;
_LIBCPP_INLINE_VAR constexpr size_t tuple_size_v = tuple_size&lt;_Tp&gt;::value;

[...]/usr/include/c++/v1/tuple:1548:39: error: non-type template argument is not a constant expression
        typename __make_tuple_indices&lt;tuple_size_v&lt;remove_reference_t&lt;_Tuple&gt;&gt;&gt;::type{})

The next question is that even if I can do this, should I? Will it increase compile times to execute all this parameter pack code at compile time rather than just dispatching to a set of fixed arity function overloads?

答案1

得分: 2

My attempt generates some compile errors regarding the integer_sequence that I don't really understand.
我的尝试生成了一些关于我并不真正理解的整数序列方面的编译错误。

The second argument of std::apply expects a tuple, index_sequence is not a tuple, so tuple_size<index_sequence> is ill-formed.
std::apply 的第二个参数期望一个元组,index_sequence 不是一个元组,因此 tuple_size<index_sequence> 是非法的。

The next question is that even if I can do this, should I?
接下来的问题是,即使我能做到这一点,我是否应该这样做?

With C++20, you can simply do
使用C++20,你可以简单地这样做:

template <typename Fun, typename... Args>
auto let2(Fun fun, Args... args) {
  return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
    return LetN(fun(Var<Is, get_out_type_t<Args>>()...), args...);
  }(std::index_sequence_for<Args...>{});
}
英文:

> My attempt generates some compile errors regarding the
> integer_sequence that I don't really understand.

The second argument of std::apply expects a tuple, index_sequence is not a tuple, so tuple_size&lt;index_sequence&gt; is ill-formed.

> The next question is that even if I can do this, should I?

With C++20, you can simply do

template &lt;typename Fun, typename... Args&gt;
auto let2(Fun fun, Args... args) {
  return [&amp;]&lt;std::size_t... Is&gt;(std::index_sequence&lt;Is...&gt;) {
    return LetN(fun(Var&lt;Is, get_out_type_t&lt;Args&gt;&gt;()...), args...);
  }(std::index_sequence_for&lt;Args...&gt;{});
}

huangapple
  • 本文由 发表于 2023年4月11日 13:12:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75982580.html
匿名

发表评论

匿名网友

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

确定