2

我有这样的功能

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

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

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

问题是,在 a 中传递参数的最佳方式是什么tuplestd::tuple<Args&&...>我的理解是,Args不再转发引用,而是严格的右值引用。如何获得args包裹在 a 中的转发引用行为tuple,例如接受 anstd::forward_as_tuple并保留单个元组元素的引用类型。另外,在这里传递元组的最佳方式是什么,

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

或者

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

或者

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

?

我是否需要std::forward在函数内部的元组元素上使用,或者只是std::get它们?

4

1 回答 1

2

std::tuple<Args&&...>我的理解是,Args不再转发引用

正确的。

但严格的右值引用

是的,除非Args明确指定,在这种情况下引用折叠可以将它们变成左值引用,即,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>>.

如果您确实想了解Args...内部foo信息(没有任何额外的抽象级别),您可能想要推断出确切的类型,而不需要任何引用:

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

请注意,如果有人std::forward_as_tuple在内部使用左值和右值,则值类别将被存储在Args其中,您仍然可以使用(std::forward不仅限于转发引用,将其视为条件转换)转发这些参数。std::forward

另外,在这里传递元组的最佳方法是什么

可能Tuple&&如前所述。如果没有,那么再次取决于使用情况。如果您使用const std::tuple<Args...>&,那么通过查看 的重载列表std::get,您会看到值类别和常量传播到std::get(模引用折叠)的返回值。与std::tuple<Args...>&&. 此外,使用后者,您将不得不使用元组右值作为参数(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");
}

演示

于 2017-02-16T09:30:08.830 回答