C++可变参数模板函数-已知参数包只有一个示例[已关闭]

pbpqsu0x  于 2022-12-20  发布在  其他
关注(0)|答案(1)|浏览(163)

3天前关闭。
这篇文章是编辑和提交审查3天前。
Improve this question
我想使用一个fold表达式,但是这个函数只能和一个已知的参数包一起使用。

template <class... Types>
Foo fn_impl(Arg arg) {
  // here, a fold expression involving Types... that returns a Foo
}

Foo fn(Arg arg) {
    return fn_impl<Bar, Baz>(arg);
}

就这样,fn_impl将永远不会再被使用。有没有什么方法可以让它变得更简洁?理想情况下,我希望在它的主体中编写fn的实现,而不使用单独的实现函数(这会增加噪音,imo)。
我知道我可以用参数包中的类型手工"展开" fold表达式,但在本例中,使用fold表达式非常方便,可以使fn的实现不太冗长。
下面是一个完整的示例,请参见突出显示的QUESTION注解:

#include <cassert>
#include <cstdio>
#include <memory>

struct Base {
  virtual ~Base() {}
  virtual const char *get_name() const = 0;
};

template <class Derived> struct Base_CRTP : public Base {
  const char *get_name() const final {
    return static_cast<const Derived *>(this)->name;
  }
};

struct A : Base_CRTP<A> {
  static constexpr const char *name = "A";
};
struct B : Base_CRTP<B> {
  static constexpr const char *name = "B";
};

#define ITest_DERIVED_CLASSES A, B

// QUESTION: Can this be entirely moved into the definition of #1?
template <class IType, class... Types>
std::unique_ptr<IType> make_by_class_index___impl(int class_index) {
  int i = 0;
  std::unique_ptr<IType> ret;
  ([&] {
    if (i++ == class_index)
      ret = std::make_unique<Types>();
    return ret != nullptr;
  }() ||
   ...);
  return ret;
}

// #1
std::unique_ptr<Base> make_by_class_index(int class_index) {
  return make_by_class_index___impl<Base, ITest_DERIVED_CLASSES>(class_index);
}

template <class... Types> void print_pack_names() { (puts(Types::name), ...); }

int main() {

  print_pack_names<ITest_DERIVED_CLASSES>();

  puts("");

  auto p = make_by_class_index(0);
  assert(p != nullptr);
  printf("p name: %s\n", p->get_name());

  auto p2 = make_by_class_index(1);
  assert(p2 != nullptr);
  printf("p2 name: %s\n", p2->get_name());

  auto p3 = make_by_class_index(99);
  assert(p3 == nullptr);
}
9ceoxa92

9ceoxa921#

在缺乏足够细节的情况下,让我们不失一般性地假设ArgintFooBarBaz定义如下:

struct Foo { int x; };
struct Bar { static constexpr int foo() { return 1; } };
struct Baz { static constexpr int foo() { return 2; } };

如果你可以使用C++20,你可以迁移a)一个包含fold表达式的变量函数和B)一个对site的调用到它,例如:

template <typename... Types> Foo fn_impl(int arg) {
  return { arg + (Types::foo() + ...) };
}

// at call site
fn_impl<Bar, Baz>(arg);

转换成一个泛型的立即调用的lambda,利用P0428R2(在C++20中引入)允许为泛型lambda模板头:

Foo fn(int arg) {
  return []<typename... Types>(int arg) -> Foo {
    return { arg + (Types::foo() + ...) };
  }
  .operator()<Bar, Baz>(arg);
}

这看起来相当复杂,尤其是当你需要使用操作符名称语法来为泛型lambda提供显式的模板参数时,分离函数的方法对于未来的维护者来说更容易遵循。

相关问题