因为这个问题:Default argument in c++
说我有这样的功能:void f(int p1=1, int p2=2, int p3=3, int p4=4);
我想仅使用一些参数调用它 - 其余的将是默认值。
这样的事情会起作用:
template<bool P1=true, bool P2=true, bool P3=true, bool P4=true>
void f(int p1=1, int p2=2, int p3=3, int p4=4);
// specialize:
template<>
void f<false, true, false, false>(int p1) {
f(1, p1);
}
template<>
void f<false, true, true, false>(int p1, int p2) {
f(1, p1, p2);
}
// ... and so on.
// Would need a specialization for each combination of arguments
// which is very tedious and error-prone
// Use:
f<false, true, false, false>(5); // passes 5 as p2 argument
但它需要太多的代码才能实用。
有更好的方法吗?
答案 0 :(得分:11)
使用命名参数成语(→FAQ link)。
Boost.Parameters库(→link)也可以解决此任务,但代码冗长并大大降低了清晰度。它在处理构造函数方面也存在缺陷。当然,它需要安装Boost库。
干杯&amp;第h。,
答案 1 :(得分:7)
查看Boost.Parameter库。
它在C ++中实现命名参数。例如:
#include <boost/parameter/name.hpp>
#include <boost/parameter/preprocessor.hpp>
#include <iostream>
//Define
BOOST_PARAMETER_NAME(p1)
BOOST_PARAMETER_NAME(p2)
BOOST_PARAMETER_NAME(p3)
BOOST_PARAMETER_NAME(p4)
BOOST_PARAMETER_FUNCTION(
(void),
f,
tag,
(optional
(p1, *, 1)
(p2, *, 2)
(p3, *, 3)
(p4, *, 4)))
{
std::cout << "p1: " << p1
<< ", p2: " << p2
<< ", p3: " << p3
<< ", p4: " << p4 << "\n";
}
//Use
int main()
{
//Prints "p1: 1, p2: 5, p3: 3, p4: 4"
f(_p2=5);
}
答案 2 :(得分:4)
尽管Boost.Parameters很有趣,但它(很遗憾)会遇到许多问题,其中包括占位符冲突(并且必须调试古怪的预处理器/模板错误):
BOOST_PARAMETER_NAME(p1)
将创建您稍后使用的_p1
占位符。如果您有两个不同的标头声明相同的占位符,则会出现冲突。不好玩。
基于Builder
模式,有一个更为简单(概念上和实际上)的答案,有些是命名参数成语。
而不是指定这样的函数:
void f(int a, int b, int c = 10, int d = 20);
您指定的结构将覆盖operator()
:
通常,它与 Chaining 结合使用,其中包括使setter返回对当前对象的引用,以便可以将调用链接在一行上。
class f {
public:
// Take mandatory arguments, set default values
f(int a, int b): _a(a), _b(b), _c(10), _d(20) {}
// Define setters for optional arguments
// Remember the Chaining idiom
f& c(int v) { _c = v; return *this; }
f& d(int v) { _d = v; return *this; }
// Finally define the invocation function
void operator()() const;
private:
int _a;
int _b;
int _c;
int _d;
}; // class f
调用是:
f(/*a=*/1, /*b=*/2).c(3)(); // the last () being to actually invoke the function
我已经看到一个变量将强制参数作为参数添加到operator()
,这避免了将参数保留为属性,但语法有点怪异:
f().c(3)(/*a=*/1, /*b=*/2);
一旦编译器内联了所有构造函数和setter调用(这就是为什么它们在这里被定义,而operator()
不是),与“常规”函数调用相比,它应该产生类似的高效代码。 / p>
答案 3 :(得分:2)
这不是一个真正的答案,但是......
David Abrahams和Aleksey Gurtovoy撰写的C++ Template Metaprogramming(2004年出版!)作者谈到了这一点:
在编写本书时,我们重新考虑了用于命名的界面 功能参数支持。通过一些实验我们 发现可以通过使用提供理想的语法 具有重载赋值运算符的关键字对象:
f(slew = .799, name = "z");
他们接着说:
我们不打算深入了解这个命名的实现细节 参数库在这里;我们建议,这很简单 你自己尝试将它作为一种练习来实现。
这是在模板元编程和Boost :: MPL的上下文中。我不太确定他们的“直截了当”实现如何使用默认参数,但我认为它是透明的。