8

boost::optional<T>(1.51) は、ユーザーにとって非常に危険であり、防止したいオブジェクトを構築する方法を提供します。独自の整数クラスがあり、オプションのそのような整数を渡し、それをいくつかのクラスに格納したいとしましょう:

class myint {
public:
    int m_a;
    myint (int r_a) : m_a(r_a) {
    }
};

struct myclass {
    boost::optional<myint> content;
    myclass (const boost::optional<myint>& arg) : content(arg) {
    }
};

そして今、ユーザーがクラスを使用する方法は次のとおりです。

myclass(myint(13));            //correct use
myclass(boost::none);          //correct use
myclass(myint(0));             //correct use
myclass(0);                    //INCORRECT use, this easy typo
                               //equates boost::none which
                               //is not what the user meant

ここで何が起こっているのかを理解し、この動作を防ぎたいと思います。


興味深いことに、

myclass(1);              //does not compile

boost::none私のフィールドでは完全に有効な値ですがboost::none、ユーザーが入力しようとしているときにこっそりと入力すると、0ひどく誤解を招き、危険です。

myintクラスを実際にロールアウトするわけclass myclassではなく、ほとんどまたはまったく目的を果たさない を実際に持っていないため、意図は少し隠されている可能性があります。とにかく、関数に 10 個程度のオプションの int を送信する必要があり、重複排除は機能しません。(私があなたの年齢、身長、財産を尋ねたのと、質問に答えたくない場合に確認するための 3 つの特別なボタンがあることを想像してみてください)


以下に機能するように見える回答を投稿しました(MooingのDuck&Ilonesmizの提案から作成されましたが、より軽量です)。でも、コメントいただけると嬉しいです。

4

4 に答える 4

3

コンストラクターに を渡さないでくださいboost::optional。代わりに、このようなことを行います。

struct myclass {
    boost::optional<myint> content;
    myclass () = default;
    explicit myclass(const myint& int_):content(int_){}
};

しかし、私がそれについて考えているとき、あなたが何を達成しようとしているのか、何を避けたいのかが完全にはわかりません. optionalメンバーの目的は何ですか?

于 2013-03-06T18:09:16.677 に答える
3

これは私が好むよりも醜いですが、あなたの懸念に対処しているようです. これは、 に与えられた引数を完全にまたは のmyclassいずれかを取る関数のペアに転送し、暗黙的なユーザー定義のコンストラクターをバイパスすることによって機能します。これが機能するのは、よりも適切に一致し、暗黙的なユーザー定義のコンストラクターが最悪の一致であるためです。intboost::none_t0intboost::none_t

class myint {
public:
    int m_a;
    myint (int r_a) : m_a(r_a) {}
};    
boost::optional<myint> myintctor(int arg) {return myint(arg);}
boost::optional<myint> myintctor(boost::none_t arg) {return arg;}

struct myclass {
    boost::optional<myint> content0;
    boost::optional<myint> content1;
    boost::optional<myint> content2;

    template<class T0, class T1, class T2>
    myclass(const T0& a0, const T1& a1, const T2& a2) 
    :content0(myintctor(a0)), content1(myintctor(a1)), content2(myintctor(a2))
    {}
};

概念実証。現代のコンパイラは、コピーを排除するのに十分スマートであるべきですが、それはint.

于 2013-03-06T18:54:33.403 に答える
1

このコード(Ilonesmizからインスピレーションを得たもの)はうまく機能しているようで、Mooing Duckからのアプローチよりも少し軽いですが、それでも魔法のテンプレートトリックを使用しています。

struct myprotectedclass {
    boost::optional<myint> content;

    template <class T>
    myprotectedclass(const T& a) :content(boost::optional<myint>(a)) {}


};

これがその証拠です。
C ++がを見ると、0「うーん、これはおそらくintですが、何かへのポインタかもしれません!」と考えます。(のみ0、他の数値はありません)しかし0、それを関数に渡す場合は、型を決定する必要があるため、デフォルトの。を選択しますint。一方、オリジナルでは、 aまたはポインター(はポインター)0を期待する関数にaが渡されました。はmyintではありませんが、ポインタになる可能性があるため、それを選択していました。myintboost::none_t0

于 2013-03-07T13:50:12.687 に答える
1

問題は optional に対してのみ意味があると思いますint。解決策の 1 つは、次の 2 つのコンストラクターを提供することです。

myclass() : content(boost::none) {}
myclass(myint input) : content(input) {}

boost::optional…のアドバンテージを少し失うのは事実です。

于 2013-03-06T18:24:45.220 に答える