1

私は旗を持っています

int A = 1;
int B = 2;
int C = 4;

関数に指定できるフラグは 1 つだけであることを確認したい

check(A | B | C) ; // invalid
check(A); // valid
check(B); // valid
check(B | C); // invalid
void check(int flags) {
    // check that if A is specified, then B and C can't
    // check that if B is specified, then A and C can't
    // check that if C is specified, then B and A can't
}

大量の「if」ステートメントなしでこれを達成するにはどうすればよいですか?

4

5 に答える 5

6

位置nにビットを設定するには、値2^nを設定します。

したがって、フラグの 1 つだけが指定されていることを確認したい場合は、数値が 2 のべき乗であるかどうかを確認するだけです。

そして、これを行う方法についての質問があります:数値が 2 のべき乗であるかどうかを確認する方法

GrahamS が言うように、この質問は、正確に 1 ビットを設定する必要がある (つまり、ゼロにすることはできません) と読むことができます。そのためには、さらに、それが非ゼロであり、C 以下であることを確認してください。

于 2013-07-30T12:38:13.143 に答える
2

おそらく最もエレガントなソリューションではありませんが、うまくいくはずです:

bool check(int flags) {
    int A = 1;
    int B = 2;
    int C = 4;

    return 
        flags == 0 ||
        flags == A ||
        flags == B ||
        flags == C;
}
于 2013-07-30T12:38:14.817 に答える
0

スイッチを使用した実装は次のとおりです。

void check(int flags) {
  swicth (flags & (A | B | C)) {
    case A:
    case B:
    case C:
    case 0:
      return true;
    default:
      return false;
  }
}

とがリテラルの場合A、つまり でマークされている場合にのみ (C# で) 機能します。それ以外の場合は、次の方法で同じことができます。BCconst

void check(int flags) {
  int relevantPart = flags & (A | B | C);
  return relevantPart == A || relevantPart == B || relevantPart == C || relevantPart == 0;
}

それ以外の場合は、2 のべき乗のトリックを使用します (Joe の回答から):

void check(int flags) {
  int relevantPart = flags & (A | B | C);
  return (relevantPart & (relevantPart - 1)) == 0;
}

最下位 3 ビットよりも上位のビットが存在する可能性があり、それらは無視されると想定しました。Aまた、 、B、も も有効ではないと仮定しましたC(これは私の解釈では共存していません)。

于 2013-07-30T13:15:25.017 に答える
0

私はコメントするつもりでしたが、GrahamS が言ったことは、要点を詳しく説明するのに十分なほど重要でした。

フラグは通常、特に倍数を設定できるようにしたい場合に使用されます。これは私たちのタスク列挙型の例です

namespace Shared.Enumerations
{
    [Flags]
    public enum TaskStatusEnum
    {
        NotSet = 0,
        Open = 1,
        Canceled = 2,
        Complete = 4,
        OnHold = 8,
        Inactive = 32,
        All = Open | Canceled | Complete | OnHold | Inactive
    }
} 

これは、オープンまたは保留中のタスクを提供できるようにするためです。

 TaskList activeTasks = taskListManager.TaskList.FindAll(target.Name, target.TaskType, (TaskStatusEnum.Open | TaskStatusEnum.OnHold));

もちろん、通常の列挙では、一度に 1 つのことしか設定できません。実際には、次のようなことができます。

[TestMethod]
public void checkEnumVals()
{
        var ts = TaskStatusTestEnum.Open;
        ts |= TaskStatusTestEnum.OnHold;

        bool matchBoth = false;
        if ((ts & TaskStatusTestEnum.OnHold) == TaskStatusTestEnum.OnHold && (ts & TaskStatusTestEnum.Open) == TaskStatusTestEnum.Open)
           matchBoth = true;

        Assert.IsTrue(matchBoth);
}

ただし、このようなことはお勧めしません。

于 2013-07-30T13:16:26.717 に答える