2016-11-02 7 views
3

通常、関数がboost::optionalを返すとき空の値を指定するために空のブレース{}を返す人がたくさんいますが、これは正常に動作し、boost::noneを返すよりも短いです。boostオプションとstd :: experimentalのオプション割り当ての違い

私はboost::optional<int>を空にするのと同様のことを試みましたが、コピー代入演算子(またはほとんどの場合は移動代入演算子)を右側の空のブレースで呼び出すと、空のブレースはintに変換されてからその値はオプションに割り当てられているので、私は期待していた変数を0に設定し、空の値にはしません。ここではhttps://godbolt.org/g/HiF92vの例があります。std::experimental::optionalで同じことを試してみたら、期待通りの結果が得られます(この例ではstd :: experimental :: optionalを置き換えれば、命令はmov eax, eaxになります)。

boostオプション(非整数型)の別のテンプレート引数を使用すると、一部のコンパイラがコンパイルされます(私が期待している動作、ここでの例はhttp://cpp.sh/5j7n)。したがって、同じlibの場合でも、テンプレートargに応じて動作が異なります。

私はここで何が起こっているのか理解したいと思っています。私はそれがデザインに考慮されていないライブラリにC++ 14の機能を使用しているということとは関係があります。私はboost/optionalヘッダーを読んだが、細部に迷ってしまった。同様の結果でインライン展開せずにコンパイル済みコードを調べようとした。

私は、-std = C++ 14でgcc 4.9.2を使用し、1.57をブーストしています。

btw:私はboost::optional::resetまたはboost::noneを使用していたはずですが、コードベースの残りのセマンティクスと一貫性を保ちようとしていました。

+0

割り当てと初期化の違いは... – aschepler

+0

はい、確かに問題は、boost :: optionalとstd :: experimental :: optionalの割り当てが異なる理由と、boost :: optionalの理由です非整数型の場合 – dlavila

+1

基本的に、 'std :: experimental :: optional'は、' o = {} 'が常にそれをリセットするような特別なやり方をしています。 'boost :: optional'にはそのようなトリックはありません。 –

答えて

5

最初にこの例を考えて、何が起こっているか理解するために:オーバーロードの解決が決定的であるため、

void fun(int) { puts("f int"); } 
void fun(double) { puts("f double"); } 

int main() { 
    fun({}); // error 
} 

これは、コンパイラエラーになり:doubleintは等しくよく合います。しかし、非スカラー型が出現した場合、状況は異なります。

struct Wrap{}; 
void fun(int) { puts("f(int)"); } 
void fun(Wrap) { puts("f(Wrap)"); } 

int main() { 
    fun({}); // ok: f(int) selected 
} 

これは、スカラーがよりよく一致するためです。何らかの理由で、私は同じ2つのオーバーロードをしたいが、同時に私は、過負荷fun(Wrap)を選択しfun({})をしたいと思い、私は定義ビットを微調整することができ、場合:

template <typename T> 
std::enable_if_t<std::is_same<int, std::decay_t<T>>::value> 
fun(T) { puts("f int"); } 

void fun(Wrap) { puts("f(Wrap)"); } 

つまり、fun(Wrap)は変わらないが、最初のオーバーロードは現在、Tのテンプレートになりました。しかし、enable_ifを使用すると、制約が適用されるので、タイプはintです。だから、これはかなり人工的なテンプレートですが、それは仕事をします。私が電話した場合:

fun(0); // picks fun(T) 

人工テンプレートが選択されます。

fun({}); // picks fun(Wrap) 

人工テンプレートがまだテンプレートですので、この場合には型推論で考慮されることはありません、それが選択されますので、唯一の目に見える過負荷は、fun(Wrap)次のとおりです。しかし、私は入力した場合。

std::optional<T>でも同じトリックが使用されています。Tからの割り当てはありません。代わりに、これにはUをとる類似の人為的割り当てテンプレートがありますが、後で制約されるので、T == Uです。参照実装hereで確認できます。

boost::optional<T>は、この 'リセットイディオム'を認識しないC++ 11より前に実装されています。したがって、通常の割り当てはTです。Tがスカラーの場合は、Tからの割り当てが優先されます。したがって違い。

これを考えると、Boost.Optionalにはstd::optionalとは逆のバグがあると思います。 Boost.Optionalで実装できない場合でも、実行時の驚きを避けるために少なくともコンパイルに失敗するはずです。

関連する問題