9

保護されたコンストラクターを使用してクラスを作成したので、新しいインスタンスは、shared_ptrをクラスに返す静的なcreate()関数でのみ生成できます。効率的な割り当てを提供するために、create関数内でboost :: make_sharedを使用したいのですが、コンパイラーは、クラスコンストラクターがboost::make_shared内で保護されていると文句を言います。私はboost::make_sharedをクラスの友達にすることにしましたが、構文に戸惑っています。私は試した

template< class T, class A1, class A2 >
friend boost::shared_ptr<Connection> boost::make_shared(const ConnectionManagerPtr&, const std::string&);

しかし、コンパイラは私に構文エラーを与えました。助けてください。

4

6 に答える 6

9

friendパーツをテンプレート化する必要はありませんが、friend関数がテンプレートであることを示す必要があります。

friend boost::shared_ptr<Connection> boost::make_shared<>(/* ... */);
//                                                     ^^

これはComeauと現在のGCCバージョンで機能しますが、VCでは失敗します。次の形式の方がよいでしょう。

friend boost::shared_ptr<Connection> boost::make_shared<Connection>(/* ... */);

これは現在、複数のコンパイラで機能します。VC8、VC10、GCC 4.2、GCC 4.5、Comeau4.3でテストしました。

あるいは、Martinが行うように、関数テンプレートの特定のインスタンスを参照するために修飾名を使用することは、Comeauで機能するはずですが、GCCはそれを窒息させます。

の実装の詳細に依存しないmake_shared()(したがって、VC10のTR1実装でも機能する)便利な代替手段は、コンストラクターのアクセス保護にpass-key-idiomを使用し、create()代わりに関数をフレンドリングすることです。

class Connection {
// ...
public:
    class Key {
        friend boost::shared_ptr<Connection> create(const ConnectionManagerPtr&, 
                                                    const std::string&);
        Key() {}
    };
    Connection(const ConnectionManagerPtr&, const std::string&, const Key&);
};

boost::shared_ptr<Connection> create(const ConnectionManagerPtr& p, 
                                     const std::string& s) 
{
    return boost::make_shared<Connection>(p, s, Connection::Key());
}
于 2010-07-31T18:25:40.977 に答える
2

make_sharedを使用するのに適切な場所ではないと思います。演算子newを使用してオブジェクトを作成し、そのポインターをshared_ptrコンストラクターに渡すだけです。そうすれば、誰かと友達になる必要はありません。

ところで、なぜテンプレート引数と関数引数が異なるタイプなのですか?

于 2010-07-31T15:03:39.630 に答える
2

パーツなしでやってみtemplateます。結局のところ、(テンプレート)関数の特定のインスタンス化をクラスの友達にしたいのではないでしょうか。しますか

friend boost::shared_ptr<Connection> boost::make_shared(const ConnectionManagerPtr&, const std::string&);

仕事?

それが解決策でない場合は、取得しているコンパイラメッセージを提供すると役立つ場合があります...

于 2010-07-31T14:40:09.097 に答える
1

共有所有権を強制するために、以下の単純なソリューションを使用することになりました。友情は必要ありません。

class probe {
    probe() = default;
    probe(...) { ... }

    // Part I of III, private
    struct creation_token {};
    probe(probe const&) = delete;
    probe& operator=(probe const&) = delete;

public:
    // Part II of III, public
    template <class... Args>
    probe(creation_token&&, Args&&... args):
        probe(std::forward<Args>(args)...) {}

    // Part III of III, public
    template <class... Args>
    static auto create(Args&&... args) {
        return make_shared<probe>(creation_token(),
            std::forward<Args>(args)...);
    }
};
于 2016-01-28T11:55:54.477 に答える
-1

以下は私があなたのためにこれをするために書いたいくつかのマクロです。あなたの場合、あなたは以下を使うでしょう:

BOOST_MAKE_SHARED_2ARG_CONSTRUCTOR(Connection, const ConnectionManagerPtr&, const std::string&);

マクロ定義:

// Required includes
#include <boost/make_shared.hpp>
#include <boost/type_traits/add_reference.hpp>
#include <boost/type_traits/add_const.hpp> 

// Helper macro
#define CONST_REFERENCE(T) boost::add_reference<boost::add_const<T>::type>::type

/** BOOST_MAKE_SHARED_nARG_CONSTRUCTOR(CLASS_NAME, ARG1_TYPE, ARG2_TYPE, ...) 
  *
  * Use this macro inside the body of a class to declare that boost::make_shared
  * should be considered a friend function when used in conjunction with the
  * constructor that takes the given argument types.  This allows the constructor 
  * to be declared private (making it impossible to accidentally create an instance 
  * of the object without immediatly storing it in a boost::shared_ptr).  
  * Example usage:
  *
  * class Foo {
  *   private:
  *     Foo(int size, const char* name);
  *     MAKE_SHARED_2ARG_CONSTRUCTOR(Foo, int, const char*);
  * };
  * 
  * boost::shared_ptr<Foo> myFoo = boost::make_shared<Foo>(3, "Bob");
  *
  * Note that you need to explicitly specify the number of arguments 
  * that the constructor takes as part of the macro name.  Also, note that 
  * macros don't mix well with templated types that contain commas -- so 
  * if you have such a type, then you should typedef it to a shorter name 
  * before using it with this macro.
  */
#define BOOST_MAKE_SHARED_0ARG_CONSTRUCTOR(CLASS_NAME) \
    friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>()
#define BOOST_MAKE_SHARED_1ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1) \
    friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1))
#define BOOST_MAKE_SHARED_2ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2) \
    friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2))
#define BOOST_MAKE_SHARED_3ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2, ARG_TYPE3) \
    friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2), CONST_REFERENCE(ARG_TYPE3))
#define BOOST_MAKE_SHARED_4ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2, ARG_TYPE3, ARG_TYPE4) \
    friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2), CONST_REFERENCE(ARG_TYPE3), CONST_REFERENCE(ARG_TYPE4))
#define BOOST_MAKE_SHARED_5ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2, ARG_TYPE3, ARG_TYPE4, ARG_TYPE5) \
    friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2), CONST_REFERENCE(ARG_TYPE3), CONST_REFERENCE(ARG_TYPE4), CONST_REFERENCE(ARG_TYPE5))
#define BOOST_MAKE_SHARED_6ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2, ARG_TYPE3, ARG_TYPE4, ARG_TYPE5, ARG_TYPE6) \
    friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2), CONST_REFERENCE(ARG_TYPE3), CONST_REFERENCE(ARG_TYPE4), CONST_REFERENCE(ARG_TYPE5), CONST_REFERENCE(ARG_TYPE6))
#define BOOST_MAKE_SHARED_7ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2, ARG_TYPE3, ARG_TYPE4, ARG_TYPE5, ARG_TYPE6, ARG_TYPE7) \
    friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2), CONST_REFERENCE(ARG_TYPE3), CONST_REFERENCE(ARG_TYPE4), CONST_REFERENCE(ARG_TYPE5), CONST_REFERENCE(ARG_TYPE6)), CONST_REFERENCE(ARG_TYPE7))
#define BOOST_MAKE_SHARED_8ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2, ARG_TYPE3, ARG_TYPE4, ARG_TYPE5, ARG_TYPE6, ARG_TYPE7, ARG_TYPE8) \
    friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2), CONST_REFERENCE(ARG_TYPE3), CONST_REFERENCE(ARG_TYPE4), CONST_REFERENCE(ARG_TYPE5), CONST_REFERENCE(ARG_TYPE6)), CONST_REFERENCE(ARG_TYPE7)), CONST_REFERENCE(ARG_TYPE8))
#define BOOST_MAKE_SHARED_9ARG_CONSTRUCTOR(CLASS_NAME, ARG_TYPE1, ARG_TYPE2, ARG_TYPE3, ARG_TYPE4, ARG_TYPE5, ARG_TYPE6, ARG_TYPE7, ARG_TYPE8, ARG_TYPE9) \
    friend boost::shared_ptr<CLASS_NAME> boost::make_shared<CLASS_NAME>(CONST_REFERENCE(ARG_TYPE1), CONST_REFERENCE(ARG_TYPE2), CONST_REFERENCE(ARG_TYPE3), CONST_REFERENCE(ARG_TYPE4), CONST_REFERENCE(ARG_TYPE5), CONST_REFERENCE(ARG_TYPE6)), CONST_REFERENCE(ARG_TYPE7)), CONST_REFERENCE(ARG_TYPE8)), CONST_REFERENCE(ARG_TYPE9))
于 2011-03-29T14:51:35.490 に答える
-2

完全なバージョンがどのように見えるかの要約:

#include <iostream>
#include <boost/make_shared.hpp>

class Foo {
  explicit Foo(int x) {
    std::cout << "Foo::Foo(" << x << ")\n";
  }
public:
  friend boost::shared_ptr<Foo> boost::make_shared<Foo, int>(const int& x);

  static boost::shared_ptr<Foo> create(int x) {
    return boost::make_shared<Foo, int>(x);
  }

  ~Foo() {
    std::cout << "Foo::~Foo()\n";
  }
};

int main(int argc, const char *argv[]) {
  Foo::create(42);
}
于 2010-08-03T10:38:51.457 に答える