将一包转发引用包装成元组

Wrap a pack of forwarding references in a tuple

本文关键字:引用 包装 元组 转发 一包      更新时间:2023-10-16

我具有这样的函数

template <typename... Args> void foo(Args&&... args);

我需要在最后添加一个带有默认参数的额外参数。由于包装需要最后一次,我正在考虑将功能更改为

template <typename... Args> void foo(std::tuple<Args&&...> args,
                                     const std::string& name = {});

问题是,通过tuple中的参数的最佳方法是什么。我的理解是,在std::tuple<Args&&...>中,Args不再转发参考文献,而是严格的RVALUE参考。如何获得args包裹的CC_4的转发参考行为,例如接受std::forward_as_tuple并保留单个元组元素的参考类型。另外,在这里通过元组的最佳方法是什么,

std::tuple<Args&&...> args

const std::tuple<Args&&...>& args

std::tuple<Args&&...>&& args

我需要在功能内的元组元素上使用std::forward,还是简单地使用std::get

我的理解是,在std::tuple<Args&&...>中,Args不再转发参考文献

正确。

,但严格rvalue参考

是的,除非明确指定Args,否则在这种情况下参考折叠可以将它们变成LVALUE参考,即foo<int&>(...)将导致Args&& -> int& && -> int&

什么是通过元组传递参数的最佳方法。

取决于foo的预期用法。如果您不需要确切知道Args...是什么,则可以逃脱:

template <typename Tuple>
void foo(Tuple&& args, const std::string& name = {});

在这种情况下,使用std::tuple_element_t<N, std::decay_t<Tuple>>仍然可以访问单个类型。

如果您 do 想在foo中知道Args...(没有任何其他抽象级别),则您可能想推断出确切的类型,而无需任何参考:

template <typename.... Args>
void foo(std::tuple<Args...>&& args, const std::string& name = {});

请注意,如果某人在内部使用 std::forward_as_tuple和lvalues and rvalues,则值类别将存储在Args中,您仍然可以使用std::forward转发这些参数(std::forward IS 仅限于转发参考,只有思考,请思考它是有条件的演员)。

另外,在此处通过元组的最佳方法是什么

可能是前面建议的Tuple&&。如果没有,则再次取决于用法。如果使用const std::tuple<Args...>&,则通过查看std::get的Overloads列表,您会发现值类别和constness将传播到std::get的返回值(MODULO参考倒数)。std::tuple<Args...>&&也是如此。另外,使用后者,您必须使用元组rvalue作为参数(foo(std::forward_as_tuple(...), ...)而不是foo(my_tuple, ...))。

替代解决方案是接受一个参数包,并检测最后一个参数是否可以受到const std::string&的约束:

#include <string>
#include <utility>
#include <tuple>
#include <type_traits>
struct dummy {};
template <typename... Args>
void foo_impl(Args&&... args)
{
    const std::string& s = std::get<sizeof...(Args) - 1>(std::forward_as_tuple(std::forward<Args>(args)...));
}
template <typename... Args>
auto foo(Args&&... args)
    -> std::enable_if_t<std::is_constructible<std::string, std::tuple_element_t<sizeof...(Args), std::tuple<dummy, Args...>>>{}>
{
    foo_impl(std::forward<Args>(args)...);
}
template <typename... Args>
auto foo(Args&&... args)
    -> std::enable_if_t<!std::is_constructible<std::string, std::tuple_element_t<sizeof...(Args), std::tuple<dummy, Args...>>>{}>
{
    foo_impl(std::forward<Args>(args)..., "default");
}

demo