pimpl 与匿名命名空间兼容吗?
我正在尝试使用 pimpl 模式并在匿名命名空间中定义实现类。这在 C++ 中可能吗?我的失败尝试如下所述。
是否可以在不将实现移动到具有名称(或全局名称)的名称空间中的情况下解决此问题?
class MyCalculatorImplementation;
class MyCalculator
{
public:
MyCalculator();
int CalculateStuff(int);
private:
MyCalculatorImplementation* pimpl;
};
namespace // If i omit the namespace, everything is OK
{
class MyCalculatorImplementation
{
public:
int Calculate(int input)
{
// Insert some complicated calculation here
}
private:
int state[100];
};
}
// error C2872: 'MyCalculatorImplementation' : ambiguous symbol
MyCalculator::MyCalculator(): pimpl(new MyCalculatorImplementation)
{
}
int MyCalculator::CalculateStuff(int x)
{
return pimpl->Calculate(x);
}
I am trying to use the pimpl pattern and define the implementation class in an anonymous namespace. Is this possible in C++? My failed attempt is described below.
Is it possible to fix this without moving the implementation into a namespace with a name (or the global one)?
class MyCalculatorImplementation;
class MyCalculator
{
public:
MyCalculator();
int CalculateStuff(int);
private:
MyCalculatorImplementation* pimpl;
};
namespace // If i omit the namespace, everything is OK
{
class MyCalculatorImplementation
{
public:
int Calculate(int input)
{
// Insert some complicated calculation here
}
private:
int state[100];
};
}
// error C2872: 'MyCalculatorImplementation' : ambiguous symbol
MyCalculator::MyCalculator(): pimpl(new MyCalculatorImplementation)
{
}
int MyCalculator::CalculateStuff(int x)
{
return pimpl->Calculate(x);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
不,在使用指针类型之前至少必须声明该类型,并且将匿名名称空间放入标头中实际上不起作用。但你为什么要这么做呢?如果你真的想隐藏实现类,请将其设为私有内部类,即
No, the type must be at least declared before the pointer type can be used, and putting anonymous namespace in the header won't really work. But why would you want to do that, anyway? If you really really want to hide the implementation class, make it a private inner class, i.e.
是的。有一个解决方法可以解决这个问题。将头文件中的指针声明为 void*,然后在实现文件中使用重新解释转换。
注意:这是否是一个理想的解决方法完全是另一个问题。正如人们常说的,我将把它作为练习留给读者。
请参阅下面的示例实现:
Yes. There is a work around for this. Declare the pointer in the header file as void*, then use a reinterpret cast inside your implementation file.
Note: Whether this is a desirable work-around is another question altogether. As is often said, I will leave that as an exercise for the reader.
See a sample implementation below:
不,你不能那样做。您必须前向声明 Pimpl 类:
并声明该类。如果您随后将定义放入未命名的命名空间中,则会创建另一个类
(匿名命名空间)::MyCalculatorImplementation
,它与::MyCalculatorImplementation
无关。如果这是任何其他命名空间
NS
,您可以修改前向声明以包含该命名空间:但是未命名的命名空间,就像它一样神奇,当该标头包含在其中时,将解析为其他内容其他翻译单元(每当您将该标头包含到另一个翻译单元中时,您都会声明一个新类)。
但这里不需要使用匿名名称空间:类声明可能是公共的,但位于实现文件中的定义仅对实现文件中的代码可见。
No, you can't do that. You have to forward-declare the Pimpl class:
and that declares the class. If you then put the definition into the unnamed namespace, you are creating another class
(anonymous namespace)::MyCalculatorImplementation
, which has nothing to do with::MyCalculatorImplementation
.If this was any other namespace
NS
, you could amend the forward-declaration to include the namespace:but the unnamed namespace, being as magic as it is, will resolve to something else when that header is included into other translation units (you'd be declaring a new class whenever you include that header into another translation unit).
But use of the anonymous namespace is not needed here: the class declaration may be public, but the definition, being in the implementation file, is only visible to code in the implementation file.
如果您确实希望在头文件中使用前向声明的类名,并在模块文件中的匿名命名空间中实现,那么请将声明的类设为接口:
If you actually want a forward declared class name in your header file and the implementation in an anonymous namespace in the module file, then make the declared class an interface:
markshiz 和 quamrana 为以下解决方案提供了灵感。
类实现
,旨在在全局头文件中声明,并充当代码库中任何 pimpl 应用程序的void*
。它不在匿名/未命名的命名空间中,但由于它只有析构函数,因此命名空间污染仍然在可接受的范围内。MyCalculatorImplementation 类
派生自Implementation 类
。由于pimpl
被声明为std::unique_ptr
,因此无需在任何头文件中提及MyCalculatorImplementation
。因此,现在 MyCalculatorImplementation 可以在匿名/未命名命名空间中实现。好处是 MyCalculatorImplementation 中的所有成员定义都位于匿名/未命名命名空间中。您必须付出的代价是必须将
Implementation
转换为MyCalculatorImplementation
。为此,提供了转换函数toImpl()
。我怀疑是否使用
dynamic_cast
还是static_cast
进行转换。我猜dynamic_cast
是典型的规定解决方案;但static_cast
也可以在这里工作,并且性能可能会更高一些。markshiz and quamrana provided the inspiration for the solution below.
class Implementation
, is intended to be declared in a global header file and serves as avoid*
for any pimpl application in your code base. It is not in an anonymous/unnamed namespace, but since it only has a destructor the namespace pollution remains acceptably limited.class MyCalculatorImplementation
derives fromclass Implementation
. Becausepimpl
is declared asstd::unique_ptr<Implementation>
there is no need to mentionMyCalculatorImplementation
in any header file. So nowMyCalculatorImplementation
can be implemented in an anonymous/unnamed namespace.The gain is that all member definitions in
MyCalculatorImplementation
are in the anonymous/unnamed namespace. The price you have to pay, is that you must convertImplementation
toMyCalculatorImplementation
. For that purpose a conversion functiontoImpl()
is provided.I was doubting whether to use a
dynamic_cast
or astatic_cast
for the conversion. I guess thedynamic_cast
is the typical prescribed solution; butstatic_cast
will work here as well and is possibly a little more performant.