gpt4 book ai didi

c++ - 如何在 C++ 中使用选项 true、false、default 和 toggle 实现标志?

转载 作者:太空狗 更新时间:2023-10-29 21:37:20 25 4
gpt4 key购买 nike

我目前正在尝试提出一种巧妙的方法来实现标志,除了通常的“true”和“false”之外,还包括状态“default”和(可选)“toggle”。

标志的一般问题是,它有一个函数并希望通过传递某些参数来定义其行为(“做某事”或“不做某事”)。

单旗

使用单个( bool 值)标志,解决方案很简单:

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 个参数之外的所有参数都是已知的。所以使用 TFlag::apply直接编译(使用 gcc)到与 return true; 相同的机器码, return false; , return prev;return !prev;会,这非常有效,但这意味着如果我想传递 TFlag,我必须使用模板函数作为论据。继承自 Flag并使用 const Flag& as 参数增加了虚函数调用的开销,但使我免于使用模板。

但是我不知道如何将其扩展到多个标志......



所以问题是:
我如何在 C++ 中的单个参数中实现多个标志,以便用户可以轻松地将它们设置为“真”、“假”或“默认”(通过不设置特定标志)或(可选)指示“任何不是默认”?

是一个有两个整数的类,使用类似的按位运算,比如模板方法,它自己的按位运算符是要走的路吗?如果是这样,有没有办法让编译器可以选择在编译时执行大部分按位运算?

编辑澄清:
我不想将 4 个不同的标志“true”、“false”、“default”、“toggle”传递给函数。
例如。想一想在标志用于“绘制边框”、“绘制中心”、“绘制填充颜色”、“模糊边框”、“让圆圈上下跳跃”、“做任何其他花哨的东西”的地方绘制的圆圈你可以用一个圆圈来做", ....
对于这些“属性”中的每一个,我想传递一个值为 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....

应该绘制边框(由标志指定),而不是绘制中心(由标志指定),模糊边界(标志表示:不是默认值)并绘制填充颜色(未指定,但它的默认值)。
如果我后来决定不再默认绘制中心但默认模糊边框,则调用应绘制边框(由标志指定),不绘制中心(由标志指定),不模糊边框(现在模糊是默认的) ,但我们不想要默认值)并绘制填充颜色(没有标志,但它的默认值)。

最佳答案

不完全漂亮,但非常简单(从您的方法 1 构建):

#include <iostream>

using Flag = int;
static const Flag Flag1 = 1<<0;
static const Flag Flag2 = 1<<2;
// add more flags to turn things off, etc.

class Foo
{
bool flag1 = true; // default true
bool flag2 = false; // default false

void applyDefault(Flag& f)
{
if (f & Flag1)
flag1 = true;
if (f & Flag2)
flag2 = true;
// apply off flags
}

public:
void operator()(/*args ,*/ Flag f)
{
applyDefault(f);
if (flag1)
std::cout << "Flag 1 ON\n";
if (flag2)
std::cout << "Flag 2 ON\n";
}
};

void foo(/*args ,*/ Flag flags)
{
Foo f;
f(flags);
}

int main()
{
foo(Flag1); // Flag1 ON
foo(Flag2); // Flag1 ON\nFlag2 ON
foo(Flag1 | Flag2); // Flag1 ON\nFlag2 ON
return 0;
}

关于c++ - 如何在 C++ 中使用选项 true、false、default 和 toggle 实现标志?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37969816/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com