接受一组对象类型的所有组合可能性作为在 C++ 中运行的参数

Accept all combinatorial possibilities for a set of object types as parameter to function in C++

给定三个不同的空 structsABC,我想要一个函数 foo 接受任意数字的任意组合这三个参数,例如:

struct A {};
struct B {};
struct C {};

// Foo has a required parameter that must be the first one given. Anything else is optional.

foo(1);
foo(1, A{});
foo(1, B{});
foo(1, B{}, A{});
foo(1, A{}, C{}, B{});

我认为可变参数模板和函数重载在这种情况下会有所帮助,所以这是我尝试过的方法:

struct A {};
struct B {};
struct C {};

template <typename... ExtraParams>
void foo(int x, ExtraParams&&...)
{
  std::cout << "x = " << x;
}

template <typename... ExtraParams>
void foo(int x, A&&, ExtraParams&&... extra)
{
  foo(x, extra...);
  std::cout << " with A";
}

template <typename... ExtraParams>
void foo(int x, B&&, ExtraParams&&... extra)
{
  foo(x, extra...);
  std::cout << " with B";
}

// same for C

但是,调用 f(2, A{}, B{}) 时,只会打印 x = 2 with A。我想我不明白为什么这不起作用,但我不太确定我应该如何处理这种情况。

EDIT 我正在测试的代码针对已知类型使用了右值引用,例如:

template <typename... ExtraParams>
void foo(int x, A&&, ExtraParams&&... extra)
{
  foo(x, extra...);
  std::cout << " with A";
}

这将产生我提到的确切行为(虽然我不知道为什么)。

问题是当您将参数 extra 作为 foo(x, extra...); 传递给 foo 的其他重载时,它们是 lvalues 并且不能绑定到右值引用,如 A&&B&&.

(强调我的)

The following expressions are lvalue expressions:

  • the name of a variable, a function, a template parameter object (since C++20), or a data member, regardless of type, such as std::cin or std::endl. Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression;

你应该使用 std::forward to forward the parameters (as rvalues if the original arguments passed are rvalues, i.e. to take advantage of forwarding reference)。例如

foo(x, std::forward<ExtraParams>(extra)...);

LIVE