【问题标题】:declare a variadic function using type alias使用类型别名声明可变参数函数
【发布时间】:2021-05-02 06:52:26
【问题描述】:

我有一个不直接获取可变参数模板参数类型的类。
相反,它获得了一种获取可变模板参数的类。
下面是一个简化的例子。

template<typename Foo> struct bar;
template<typename Derived, typename F> struct fooBase;


template<typename Derived, typename R, typename ...Args>
struct fooBase<Derived, R(Args...)> {
  using function_type = R(Args...);

  void func(Args&&... args) {
    b->func2(std::forward<Args>(args)...);
  }
  
  void set(bar<Derived>* bp) {
      b = bp;
  }

  bar<Derived>* b;
};

struct foo : public fooBase<foo, void(int)> {};

template<typename Foo> 
struct bar {
  using function_type = typename Foo::function_type;

  void func2(/** what here? */) {

  }
};


foo f;
bar<foo> b;
f.set(&b);
f.func(3);

有没有办法在bar 内部解决它而不声明父类或额外的模板参数?

【问题讨论】:

  • 如果“解决它”是指从 foo 获得 Args... 包?你可以使用struct bar&lt;foo&lt;R(Args...)&gt;&gt; { ... }
  • @super 实际上,它更复杂。我已经编辑了帖子。我的问题是我可以用function_type 声明一个函数吗
  • 这可能会有所帮助:stackoverflow.com/questions/45288396/…
  • fooBase 的意义何在?如果你删除它,你可以按照我在评论中所说的去做。在这里,您可以使 void(int) 成为 foos 签名的一部分并执行相同操作。
  • @super 这只是一个最小的可重现示例...实际代码有含义和其他复杂的东西。

标签: c++


【解决方案1】:

我的问题是我可以用function_type 声明一个函数

你可以在struct bar外写如下:

Foo::function_type func;

这是一个名为func2 的函数的前向声明,它必须在别处定义,因此不能解决问题。由于 StoryTeller 提到的 this reason,您也不能在 struct bar 内写这个。你还可以写的是:

Foo::function_type *func;

现在你已经声明了一个函数指针。你可以让它指向一个真正的函数。例如:

func = [](int x){ std::cout << x << '\n'; };

你也可以在struct bar里面声明这个函数指针,如果你可以使用C++17或更高版本,你应该把它改成static constexpr。 另一个技巧是你想要一个带有参数包的函数。不幸的是,您不能直接为参数包创建类型别名。但是,你可以写:

template<typename Foo>
struct bar {
    using function_type = typename Foo::function_type;
    /* static constexpr */ function_type *func2 = [](auto... params) {
        ...
    };
};

因为泛型 lambda 被分配给具有具体类型的函数指针 func2,所以 func2() 现在总是采用与 function_type 完全相同的参数。但是,正如 super 所提到的,这仅适用于没有任何捕获的 lambda 函数,否则 lambda 无法转换为函数指针。

但是,在这种情况下,您不需要声明函数指针并分配 lambda,您只需定义一个带有参数包的普通函数即可:

template<typename Foo>
struct bar {
    template<typename ...Params>
    void func2(Params&&... params) {
        std::cout << "Parameters:\n";
        ((std::cout << params << '\n'), ...);
    };

    /* Or with C++20 you can simplify this to:
    void func2(auto&&... params) {
        ...
    } */
};

func2() 的正确版本将由fooBase 调用。唯一可能的问题是其他人可以使用与预期不同的一组参数调用func2。这可以通过 SFINAE 或 C++20 concepts 解决。例如,使用概念:

template<typename Foo>
struct bar {
    using function_type = typename Foo::function_type;

    template<typename ...Params>
    void func2(Params&&... params)
    requires std::invocable<function_type, Params...>
    {
        std::cout << "Parameters:\n";
        ((std::cout << params << '\n'), ...);
    };
};

上面也不是很完美,比如下面的代码:

foo f;
bar<foo> b;
f.set(&b);
f.func(3.14);
b.func2(3.14);

将分别打印出33.14

【讨论】:

  • 你不能写foo::function_type func - timsong-cpp.github.io/cppwp/n4659/temp#spec-7
  • 另外,lambda 技巧也行不通。您不能将通用 lambda 分配给函数指针。它不支持转换。
  • foo::function_type funcstruct bar 中的说法是对的,但是 lambda 技巧确实有效:godbolt.org/z/W7KjKs5j7
  • @G.Sliepen 仅适用于不捕获的 lambda。所以这是一个有限的技巧。
  • 嗯...确实。我自己从未见过或做过。直到。有用的小技巧。
猜你喜欢
  • 1970-01-01
  • 2017-06-16
  • 1970-01-01
  • 2012-02-16
  • 2017-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多