3

このScopeExitクラスをコードプロジェクトから外しましたが、GCC4.5.3ではビルドされませんでした。助けに感謝します。

class ScopeExit : private boost::noncopyable
{
    typedef std::function<void()> func_t;

public:
    ScopeExit(func_t&& f) : func(f) {}
    ~ScopeExit() { func(); }

private:
    // no default ctor
    ScopeExit();

    // Prohibit construction from lvalues.
    ScopeExit(func_t&);

    // Prohibit new/delete.
    void* operator new(size_t);
    void* operator new[](size_t);
    void operator delete(void *);
    void operator delete[](void *);

    const func_t func;
};


ScopeExit exit = [&]() { };

gcc 4.5.3エラー:

In member function ‘void test()’:
error: conversion from ‘test()::<lambda()>’ to non-scalar type ‘ScopeExit’ requested

編集:

ScopeExit exit([&]() { }); // this works
4

2 に答える 2

3

コピー/移動の初期化です。コピーc-torが削除され、移動c-torも削除されます。

n3337 12.8 / 9

クラスXの定義でmoveコンストラクターが明示的に宣言されていない場合、moveコンストラクターは、次の場合にのみデフォルトとして暗黙的に宣言されます。

— xには、ユーザーが宣言したコピーコンストラクターがありません。

— xには、ユーザーが宣言したコピー代入演算子がありません。

— xには、ユーザーが宣言したムーブ代入演算子がありません。

— xには、ユーザーが宣言したデストラクタがなく、

—移動コンストラクターは、削除済みとして暗黙的に定義されません。

最初のケースが機能しない理由はわかりませんが、このケースは正常に機能します

template<typename T>
ScopeExit(T&& f) : func(std::move(f)) {}
ScopeExit(ScopeExit&& rhs) : func(std::move(rhs.func)) { }]

編集。

クラス型の変数を使用する場合copy-initialization、標準および省略記号の暗黙的な変換のみが使用されます。ラムダから関数ポインターへの変換、または関数ポインターからへの変換は使用されますstd::functionuser-defined conversion、使用されません。

n3337 8.5 / 16

初期化子のセマンティクスは次のとおりです。デスティネーションタイプは初期化されるオブジェクトまたは参照のタイプであり、ソースタイプは初期化式のタイプです。初期化子が単一の(場合によっては括弧で囲まれた)式でない場合、ソースタイプは定義されていません。

宛先タイプが(おそらくcv修飾された)クラスタイプである場合:

それ以外の場合(つまり、残りのコピー初期化の場合)、ソースタイプからデスティネーションタイプに、または(変換関数が使用される場合は)その派生クラスに変換できるユーザー定義の変換シーケンスが、13.3で説明されているように列挙されます。 1.4であり、過負荷解決(13.3)によって最適なものが選択されます。変換を実行できないか、あいまいな場合、初期化の形式が正しくありません。

n3337 13.3.1.4 / 1

8.5で指定された条件下では、クラス型のオブジェクトのコピー初期化の一部として、ユーザー定義の変換を呼び出して、初期化式を初期化されるオブジェクトの型に変換できます。過負荷解決は、呼び出されるユーザー定義の変換を選択するために使用されます。「cv1T」が初期化されるオブジェクトのタイプであり、Tがクラスタイプであると仮定すると、候補関数は次のように選択されます。

— Tの変換コンストラクター(12.3.1)は候補関数です。

  1. どちらの場合も、引数リストには初期化式である1つの引数があります。[注:この引数は、コンストラクターの最初のパラメーターおよび変換関数の暗黙のオブジェクトパラメーターと比較されます。—エンドノート]

n333713.3.2

1.特定のコンテキスト用に構築された候補関数のセット(13.3.1)から、実行可能な関数のセットが選択されます。そこから、引数変換シーケンスを比較して最適な関数を選択します(13.3.3)。実行可能な関数の選択では、変換シーケンスのランク付け以外の引数と関数パラメーターの関係が考慮されます。

第2に、Fが実行可能な関数であるためには、各引数に対して、その引数をFの対応するパラメーターに変換する暗黙の変換シーケンス(13.3.3.1)が存在する必要があります。

n3337 13.3.3.1 / 4

ただし、クラスのコピー初期化の2番目のステップで一時のコピー/移動のために呼び出されたときに13.3.1.3までに候補となるコンストラクターまたはユーザー定義の変換関数の引数を検討する場合、単一の引数としての初期化子リスト、または初期化子リストに1つの要素があり、クラスXへの変換または(おそらくcv修飾された)Xへの参照が、Xのコンストラクターの最初のパラメーターとして、または13.3.1.4によって考慮される場合、13.3.1.5、または13.3.1.6の場合はすべて、標準の変換シーケンスと省略記号の変換シーケンスのみが考慮されます。

于 2012-09-18T07:17:14.290 に答える
1

コピーコンストラクターをプライベートにすることで、コピーの初期化(最初のケースで発生していること)を禁止しました。しかし、コンストラクターScopeExit(func_t&& f) : func(f) {}はパブリックであり、それが2番目の(動作中の)宣言で呼び出されます。2つのctorのアクセス制御仕様を試してみて、これを確認する必要があります。

編集:ForEverが指摘したように、間違った用語は事実上ScopeExit(func_t&& f) : func(f) {}、移動コンストラクターではありません。しかし、これが2番目のケースで呼び出されている理由であり、それが機能する理由です。また、copy-ctorのプライバシーが、最初のケースが機能しない理由です。

于 2012-09-18T07:28:06.397 に答える