如何将具有不同数量默认参数的函数包装为只有一个参数?
How to wrap a function with a varying number of default arguments to have only one argument?
我有一个模板函数,我们称它为 "client":
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<>()
函数,而我只关心传递第一个参数const std::string&
。所以我做了以下事情:
void bindAdapteeOne(const std::string& s) {
return adaptee_one(s);
}
void bindAdapteeTwo(const std::string& s) {
return adaptee_two(s);
}
然后将bindAdapteeX()
传递给client<>()
。
我想做的是自动包装或使用一个(模板化的)包装器而不是每个适配器一个。我觉得可变参数可能就是这种情况,但对如何准确应用它们知之甚少。
C++11 可以,如果绝对必要,C++14 也可以。
C++11 is fine, C++14 is fine if absolutely necessary.
此处为 C++11 解决方案。
What I'd like to do is to automate the wrapping or have one (templated) wrapper instead of one per adaptee.
我不会那样做。您可以简单地使用非捕获 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");
}
这是宏帮助的时代之一:
#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&, int)
。因此,您不能拥有函数模板或 class 模板包装器 - 您需要使用 lambda(或包装 lambda 的宏)进行内联。
我想我会创建一个 class 来包装您的参数并让客户端接受该 class 的一个实例。这样一来,您只有一个参数,其中包含您想要的任意多个参数。
该参数包装器也会提供默认值,并允许您在派生的 classes 中为特定目的优化它们。
与 lambda 表达式相比,这可能也更加自我记录。
谁知道呢,当需要从文件中读取和写入参数时,包装器 class 将是执行此操作的最佳场所。
我有一个模板函数,我们称它为 "client":
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<>()
函数,而我只关心传递第一个参数const std::string&
。所以我做了以下事情:
void bindAdapteeOne(const std::string& s) {
return adaptee_one(s);
}
void bindAdapteeTwo(const std::string& s) {
return adaptee_two(s);
}
然后将bindAdapteeX()
传递给client<>()
。
我想做的是自动包装或使用一个(模板化的)包装器而不是每个适配器一个。我觉得可变参数可能就是这种情况,但对如何准确应用它们知之甚少。
C++11 可以,如果绝对必要,C++14 也可以。
C++11 is fine, C++14 is fine if absolutely necessary.
此处为 C++11 解决方案。
What I'd like to do is to automate the wrapping or have one (templated) wrapper instead of one per adaptee.
我不会那样做。您可以简单地使用非捕获 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");
}
这是宏帮助的时代之一:
#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&, int)
。因此,您不能拥有函数模板或 class 模板包装器 - 您需要使用 lambda(或包装 lambda 的宏)进行内联。
我想我会创建一个 class 来包装您的参数并让客户端接受该 class 的一个实例。这样一来,您只有一个参数,其中包含您想要的任意多个参数。
该参数包装器也会提供默认值,并允许您在派生的 classes 中为特定目的优化它们。
与 lambda 表达式相比,这可能也更加自我记录。
谁知道呢,当需要从文件中读取和写入参数时,包装器 class 将是执行此操作的最佳场所。