我编写了一个带有受保护构造函数的类,因此只能使用静态create()函数生成新实例,该函数将shared_ptr返回给我的类。为了提供有效的分配,我想在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&);
但是编译器给了我语法错误。请帮忙。
答案 0 :(得分:10)
您无需为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和Comeau 4.3上进行了测试。
或者使用限定名称来引用函数模板的特定实例,因为Martin 应该工作并且与Comeau一起工作,但是GCC会对其进行扼流。
不依赖于make_shared()
的实现细节(因此也适用于VC10s TR1 implementation)的有用替代方法是使用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());
}
答案 1 :(得分:2)
我会尝试没有template
部分。毕竟,您希望(模板)函数的特定实例化成为您班级的朋友,不是吗?确实
friend boost::shared_ptr<Connection> boost::make_shared(const ConnectionManagerPtr&, const std::string&);
工作?
如果那不是解决方案,那么向我们提供您正在获得的编译器消息可能会有所帮助......
答案 2 :(得分:2)
我认为这不是使用make_shared的正确位置。只需使用operator new构造对象,并将指针传递给shared_ptr构造函数。这样你就不需要和任何人成为朋友。
BTW,为什么模板参数和函数参数的类型不同?答案 3 :(得分: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)...);
}
};
答案 4 :(得分:0)
下面是我为你写的一些宏。在您的情况下,您将使用:
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))
答案 5 :(得分:-1)
简要介绍完整版本的外观:
#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);
}