【问题标题】:A class that can accept variable function references of unknown signature一个可以接受未知签名的变量函数引用的类
【发布时间】:2016-12-02 22:57:17
【问题描述】:

我想创建一个类,而不是在实例化时接受可变数量的函数引用,这些函数引用没有事先知道的签名。这是一个几乎可以满足我要求的示例:

// To show the function refs being used 
void p(int arg) { cout << "int " << arg << endl; }
void p(string arg) { cout << "string " << arg << endl; }
void p(int arg1, int arg2) { cout<<"int/int "<<arg1<<arg2<<endl; }
void p(int arg1, string arg2) { cout<<"int/string "<<arg1<<arg2<<endl; }

class foo {
    public:
    // CTOR takes variadic function refs 
    template <typename... Args>
    foo(Args... args) { p(args()...); }
    // "args()..." requires supplied functions to take no parameters 
    // but makes no requirement on their return values. 
};

// Using lambdas, but free functions, std::bind(), etc. work too
foo i([]{return 1;});              // prints "int 1" 
foo s([]{return string("one");});  // prints "string one" 
foo b([]{return 2;},
      []{return string("two");});  // prints "int/string 2two"

我看不到如何解决这个问题,以便作为参数提供的函数不会在构造函数中进行评估。我希望稍后通过foo 中的另一种方法调用p(args()...)。这就是为什么 foo 不能像foo i(1) 那样简单地创建的原因:参数函数需要稍后调用,并且需要多次调用,而不仅仅是在创建对象时调用一次(而且它们会比仅仅更复杂返回一个常量)。

问题似乎归结为保存对稍后调用的构造函数参数的引用,当类不知道这些参数将具有多少或什么签名时。不知何故,参数需要成为类模板的一部分,而不仅仅是构造函数模板,而是如何?

如果传递的所有函数都具有相同的签名,那么可以使用具有非类型参数的类模板并将函数作为模板参数提供:

template <int (&...Arg)()>
class bar {
    public:
    bar() { p(Arg()...); }
    other() { p(Arg()...); } // Use in any method
};

int one() { return 1; }
int two() { return 2; }
bar<one> bi;       // Prints "int 1"
bar<one, two> bii; // Prints "int/int 12"

但这要求所有参数都是返回 int 的函数,并且也不适用于 lambda,因为它们不能是模板参数。

【问题讨论】:

  • 我读到这个并想到 Lisp。

标签: c++ lambda variadic-templates


【解决方案1】:

您可以使用 lambda 和 std::function 来执行此操作。
请注意,lambda 可以捕获参数包并(让我说)稍后将其解包。
它遵循一个最小的工作示例:

#include<iostream>
#include<functional>

void p(int arg) { std::cout << "int " << arg << std::endl; }
void p(std::string arg) { std::cout << "string " << arg << std::endl; }
void p(int arg1, int arg2) { std::cout<<"int/int "<<arg1<<arg2<<std::endl; }
void p(int arg1, std::string arg2) { std::cout<<"int/string "<<arg1<<arg2<<std::endl; }

class foo {
public:
    template <typename... Args>
    foo(Args... args): func{[args...](){ p(args()...); }} {}

    void operator()() { func(); }

private:
    std::function<void()> func;
};

int main() {
    // create your objects...
    foo i([]{return 1;});
    foo s([]{return std::string("one");});
    foo b([]{return 2;}, []{return std::string("two");});
    // ... and use them later
    i();
    s();
    b();
}

【讨论】:

  • 我明白了,lambda 允许将参数包打包/解包到一个类型不依赖于参数包的类成员中。
  • 我的实际使用比较复杂,参数包只是函数参数的一部分,例如make_shared&lt;ObjType&gt;("name", args()..., index++) lambda 无法像我想要的那样捕获 just args()... 部分。解决方案似乎是扩展 lambda,直到它产生一个完整的表达式,其签名不依赖于参数包。比如[=](string n, int i){return make_shared&lt;ObjType&gt;(n, args()..., i);}和调整func来匹配。
  • @TrentP 好吧,答案完全基于问题。我不知道真正的问题是什么,所以我不能说什么是最好的解决方案。对不起。
猜你喜欢
  • 2011-07-03
  • 2014-05-04
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
  • 2019-11-09
  • 2011-08-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多