【问题标题】:How to wrap a function with a varying number of default arguments to have only one argument?如何用不同数量的默认参数包装一个函数,使其只有一个参数?
【发布时间】:2017-12-10 20:15:12
【问题描述】:

我有一个模板函数,我们称之为“客户端”:

template<typename T>
void client(T (*func)(const std::string&), const std::string& s) {}

然后有许多“adaptee”函数,它们都具有相同类型的第一个非默认参数,但以下参数的数量不同并且具有默认值:

void adaptee_one(const std::string&, int i = 1, char* c = nullptr) {}
void adaptee_two(const std::string&, float* f = nullptr) {}

上述功能是给定的。现在我要做的就是将它们作为第一个参数传递给上面的client&lt;&gt;() 函数,而我只关心传递第一个参数const std::string&amp;。所以我做了以下事情:

void bindAdapteeOne(const std::string& s) {
    return adaptee_one(s);
}

void bindAdapteeTwo(const std::string& s) {
    return adaptee_two(s);
}

然后将bindAdapteeX() 传递给client&lt;&gt;()。

我想做的是自动化包装或使用一个(模板化的)包装器,而不是每个适配者一个。我觉得可变参数可能就是这种情况,但对如何准确应用它们知之甚少。

C++11 很好,如果绝对必要,C++14 也很好。

【问题讨论】:

  • 是否允许使用 lambda?
  • @AndyG 它在命名空间中,在任何类之外,所以我认为是的,只要有一个理智的地方来保存它们。
  • @rici 因为doesn't work.
  • @Barry:确实正确。虽然它与operator() 一起工作得很好,但这仍然是一堆样板。 (但是对于灵活的模板而不是强制转换为函数指针,仍有一些话要说。)

标签: c++ c++11 templates c++14 default-arguments


【解决方案1】:

C++11 很好,如果绝对必要,C++14 也很好。

这里是 C++11 解决方案。

我想做的是自动化包装或使用一个(模板化的)包装器而不是每个适配者一个。

我不会那样做。您可以简单地使用非捕获 lambda 并让它们衰减为函数指针:

client (+[](const std::string& s) { return adaptee_one(s); }, "foo");

我不认为将它们包装在模板中或其他任何内容中会给您提供更易读或更易于使用的解决方案。


作为一个最小的工作示例:

#include<string>

template<typename T>
void client(T (*func)(const std::string&), const std::string& s) {}

void adaptee_one(const std::string&, int i = 1, char* c = nullptr) {}
void adaptee_two(const std::string&, float* f = nullptr) {}

int main() {
    client (+[](const std::string& s) { return adaptee_one(s); }, "foo");
}

【讨论】:

  • “加号”不是错字吗?我以前从未见过。
  • @iksemyonov 这是一个positive lambda :) 开个玩笑,它用于在其转换运算符的帮助下将 lambda 转换为函数指针(请参阅链接问题)。
  • 谢谢!天啊。很高兴我发布了这个问题 - 永远不会知道。
  • @Rakete1111 ... 正 lambda ... :-D
  • @Rakete1111 stackoverflow.com/questions/18889028/… 确实是:p
【解决方案2】:

这是宏有帮助的时候之一:

#define WRAP_FN(f) +[](std::string const& s) -> decltype(auto) { return f(s); }

虽然您可以只编写该内联的正文。


您无能为力。问题是默认参数在函数签名中不可见,所以一旦进入类型系统,就无法区分:

void works(std::string const&, int=0);
void fails(std::string const&, int  );

这两个都是void(*)(std::string const&amp;, int)。所以你不能有一个函数模板或类模板包装器——你需要用 lambda(或包装 lambda 的宏)内联。

【讨论】:

  • 谢谢!模板解决方案包含一些我必须查找的东西,但无论如何,它看起来很可怕。没有办法或不需要在这里使用可变参数来解释不同数量的参数?
  • @iksemyonov 你说你只想传递std::string,你在哪里需要“不同数量的参数”?
  • @PasserBy 使用默认参数的全部内容?完整集合中的参数数量各不相同。
  • @iksemyonov 那么你应该在你的问题中编辑它
  • @PasserBy "但以下参数的数量不同且具有默认值:"
【解决方案3】:

我想我会创建一个类来包装您的参数并让客户端接受该类的实例。这样一来,您只有一个参数,其中包含您想要的任意多个参数。

该参数包装器也将提供默认值,并允许您在派生类中为特定目的细化它们。

与 lambdas 相比,这可能也更具自我记录性。

谁知道,当需要从文件中读取和写入参数时,包装类将是执行此操作的理想场所。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-01
    • 2015-03-30
    • 1970-01-01
    • 2011-07-18
    • 1970-01-01
    • 2017-09-18
    • 2012-05-22
    相关资源
    最近更新 更多