我目前正在尝试想出一种聪明的方法来实现标志,除了通常的“true”和“false”之外,还包括状态“default”和(可选)“toggle”。
标志的一般问题是,一个人有一个功能,并希望通过传递某些参数来定义它的行为(“做某事”或“不做某事”)。
单旗
使用单个(布尔)标志,解决方案很简单:
void foo(...,bool flag){
if(flag){/*do something*/}
}
在这里添加默认值特别容易,只需将函数更改为
void foo(...,bool flag=true)
并在没有标志参数的情况下调用它。
多个标志
一旦标志的数量增加,我通常看到和使用的解决方案是这样的:
typedef int Flag;
static const Flag Flag1 = 1<<0;
static const Flag Flag2 = 1<<1;
static const Flag Flag3 = 1<<2;
void foo(/*other arguments ,*/ Flag f){
if(f & Flag1){/*do whatever Flag1 indicates*/}
/*check other flags*/
}
//call like this:
foo(/*args ,*/ Flag1 | Flag3)
这样做的好处是,您不需要为每个标志设置参数,这意味着用户可以设置他喜欢的标志,而忘记那些他不关心的标志。特别是你不会接到一个电话foo (/*args*/, true, false, true)
,比如你必须计算哪个真/假表示哪个标志。
这里的问题是:
如果你设置了一个默认参数,一旦用户指定了任何标志,它就会被覆盖。不可能像Flag1=true, Flag2=false, Flag3=default
.
显然,如果我们想要 3 个选项(真、假、默认),我们需要为每个标志传递至少 2 位。因此,虽然它可能不是必需的,但我想任何实现都应该很容易使用第 4 状态来指示切换(=!默认)。
我有两种方法,但我对它们都不太满意:
方法 1:定义 2 个标志
到目前为止,我尝试使用这样的东西:
typedef int Flag;
static const Flag Flag1 = 1<<0;
static const Flag Flag1False= 1<<1;
static const Flag Flag1Toggle = Flag1 | Flag1False;
static const Flag Flag2= 1<<2;
static const Flag Flag2False= 1<<3;
static const Flag Flag2Toggle = Flag2 | Flag2False;
void applyDefault(Flag& f){
//do nothing for flags with default false
//for flags with default true:
f = ( f & Flag1False)? f & ~Flag1 : f | Flag1;
//if the false bit is set, it is either false or toggle, anyway: clear the bit
//if its not set, its either true or default, anyway: set
}
void foo(/*args ,*/ Flag f){
applyDefault(f);
if (f & Flag1) //do whatever Flag1 indicates
}
但是我不喜欢的是,每个标志都有两个不同的位。这导致“default-true”和“default-false”标志的代码不同,并导致必要的 if 而不是applyDefault()
.
方法 2:模板
通过定义这样的模板类:
struct Flag{
virtual bool apply(bool prev) const =0;
};
template<bool mTrue, bool mFalse>
struct TFlag: public Flag{
inline bool apply(bool prev) const{
return (!prev&&mTrue)||(prev&&!mFalse);
}
};
TFlag<true,false> fTrue;
TFlag<false,true> fFalse;
TFlag<false,false> fDefault;
TFlag<true,true> fToggle;
我能够将其压缩apply
成一个按位运算,在编译时除了 1 个参数之外的所有参数都是已知的。因此,使用直接编译(使用 gcc)到与 a 、或TFlag::apply
will 相同的机器代码,这是非常有效的,但这意味着如果我想传递 a作为参数,我必须使用模板函数。继承并使用as 参数会增加虚函数调用的开销,但可以避免使用模板。return true;
return false;
return prev;
return !prev;
TFlag
Flag
const Flag&
但是我不知道如何将其扩展到多个标志...
问题
所以问题是:如何在 C++ 中的单个参数中实现多个标志,以便用户可以轻松地将它们设置为“真”、“假”或“默认”(通过不设置特定标志)或(可选)表示“任何不是默认值”?
一个具有两个整数的类,使用类似的按位运算,如带有自己的按位运算符的模板方法吗?如果是这样,有没有办法让编译器选择在编译时执行大多数按位运算?
编辑澄清:
我不想将 4 个不同的标志“true”、“false”、“default”、“toggle”传递给函数。
例如,想象一个绘制的圆圈,其中标志用于“绘制边框”、“绘制中心”、“绘制填充颜色”、“模糊边框”、“让圆圈上下跳跃”、“做任何其他花哨的事情”你可以用圆圈做的事情”,....
对于每个“属性”,我想传递一个值为真、假、默认或切换的标志。因此,该函数可能会决定默认绘制边框、填充颜色和中心,但其余的都没有。一个电话,大致是这样的:
draw_circle (DRAW_BORDER | DONT_DRAW_CENTER | TOGGLE_BLURRY_BORDER) //or
draw_circle (BORDER=true, CENTER=false, BLURRY=toggle)
//or whatever nice syntax you come up with....
应该绘制边框(由标志指定),不绘制中心(由标志指定),模糊边框(标志说:不是默认值)并绘制填充颜色(未指定,但它的默认值)。
如果我后来决定不再默认绘制中心但默认模糊边界,调用应该绘制边界(由标志指定),不绘制中心(由标志指定),不模糊边界(现在模糊是默认的,但我们不想要默认值)并绘制填充颜色(没有标志,但它是默认值)。