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");
}
演示