4

私は、このトークで Herb Sutter のラッパー クラスのアイデアに基づいたシンクロナイザー ヘルパー テンプレート クラスの作成を検討してきました。これは msvc ではそのままでは機能しません (ブレースの初期化を削除しない限り) が、ブレースの初期化が削除されれば問題ありません。 .

clang/gcc (ubuntu 12.10、gcc4.7.2、libc++ で自己ビルドされた clang (3.2)) では、プライベート アクセス修飾子をパブリックの前に表示する必要があるようです。これは少し奇妙に思えます。

gccのエラーは error: ‘t_’ was not declared in this scope

そしてclangは

error: use of undeclared identifier 't_'
  auto operator()(F f) const ->decltype(f(t_))

これは、私が認識していないテンプレート/declytpe の問題である可能性があり、誰かがこの問題を解決できるかどうか疑問に思っています。(関連する c++11 フラグでコンパイルされたすべて)

template <class T>
class Synchronised {
    public:
        Synchronised(T t = T{}) : t_{t} {}
        template <typename F>
        auto operator()(F f) const -> decltype(f(t_)) {
            std::lock_guard<std::mutex> lock{mutex_};
            return f(t_);
        }
        private: // place this before public: and this object compiles
            mutable T t_;
            mutable std::mutex mutex_;
};

編集: カット アンド ペーストが必要な場合に備えて、ヨハネスのアイデアと完全なクラスを追加します。

#include <future>
#include <iostream>
#include <thread>
#include <vector>

template <class T> T &self(T &t) { return t;  }
template<typename T> struct Dependent {  };

template<typename T>
class Synchronised : Dependent<T>{
 public:
  explicit Synchronised(T t = T()) : t_(t) {}
  template<typename Functor>
  auto operator()(Functor functor) const ->decltype(functor(self(*this).t_)) {
  //auto operator()(Functor functor) const ->decltype(functor(this->t_)) {
    std::lock_guard<std::mutex> lock(mutex_);
    return functor(t_);
  }
 private:
  mutable T t_;
  mutable std::mutex mutex_;
};


int main() {

    Synchronised<std::string> sync_string("Start\n");
    std::vector<std::future<void>> futures;
}
4

1 に答える 1

4

以下は、クラス テンプレート定義自体を有効にするだけで十分でした。ただし、ルックアップでクラス テンプレート内のデータ メンバーが見つからないのと同じ規則 (空の従属基本クラスまたは従属関数呼び出しの導入が必要) により、クラス テンプレートのインスタンス化でもデータ メンバーが見つからなくなります。これにより、コンパイラ エラーが発生します。

コンパイラには「ちょっと待って、インスタンス化時にデータメンバが見つかるかもしれない」と伝えましたが、実際にインスタンス化するとどうなるかは考えていませんでした。クラスのインスタンス化が発生した後でも名前が依存するようにします。解決は、への呼び出しまで待たなければなりませんoperator()

// keep this little util somewhere :)
template<typename T>
struct self { 
  template<typename U> U &operator()(U &t) { return t; } 
};

template <class T>
class Synchronised {
    public:
// ...
        auto operator()(F f) const -> decltype(f(self<F>()(*this).t_)) {
// ...
};

関数テンプレートの代わりにクラス テンプレートを使用すると、self引数依存のルックアップも発生せず、 の作成者が引数に一致するF呼び出される関数を作成することもできなくなります (これは、以下の部分的な解決策でも潜在的な問題になる可能性があります。 )。self*this


並べ替え以外にもいくつかのオプションがあります

  1. .囲んでいるクラスだけでなく、従属クラスの左側に式を作成する(特別なケースになるため)

    // keep this little util somewhere :)
    template <class T> T &self(T &t) { return t; }
    
    template <class T>
    class Synchronised {
        public:
    // ...
            auto operator()(F f) const -> decltype(f(self(*this).t_)) {
    // ...
    };
    
  2. 依存する基本クラスを導入して、囲んでいるクラスの特別なケーシングを回避します。

    // Keep this little util somewhere
    template<typename T> struct Dependent { };
    
    template <class T>
    class Synchronised : Dependent<T> {
        public:
    // ...
            auto operator()(F f) const -> decltype(f(this->t_)) {
    // ...
    };
    

self(*this).t_1つ目は、不明な専門分野のメンバーを作成する標準に基づいています

  • オブジェクト式の型は依存型であり、現在のインスタンス化ではありません。

this->t_2 つ目は、未知の専門分野のメンバーを作成する標準に基づいています。

  • オブジェクト式の型が現在のインスタンス化であり、現在のインスタンス化に少なくとも 1 つの依存基底クラスがあり、id-expression の名前検索で現在のインスタンス化のメンバーまたはその非依存基底クラスが見つからない。

これによりx->t_、両方のケースが従属式になるため、インスタンス化時に名前が検索されます。スタンダードは言う

クラス メンバー アクセス式 (5.2.5) は、式が現在のインスタンス化のメンバーを参照し、参照されるメンバーの型が依存型である場合、またはクラス メンバー アクセス式が未知の特殊化のメンバーを参照する場合、型依存です。

于 2013-01-13T23:10:24.143 に答える