将成员函数添加到 Boost.Variant
在我的 C++ 库中,我有一个类型 boost::variant
以及许多将此类型作为输入的算法。我没有使用成员函数,而是使用这种类型的全局函数,例如 void f( boost::variant& var )。我知道这也可以通过模板来实现,但这不适合我的设计。
我非常喜欢这种编程风格:
boost::variant<A, B> v;
f( v );
但是这个库的一些用户不习惯它,并且由于 Boost.Variant 概念被类型定义隐藏,他们感觉像调用 vf().
为了实现这一点,我可以想到两种可能性:1)覆盖 boost::variant
和 2)重新实现 boost::variant
并添加我自己的成员函数。我不确定这些想法好不好。您能给我一些帮助吗?还有其他的可能性吗?
In my C++ library I have a type boost::variant<A,B>
and lots of algorithms getting this type as an input. Instead of member functions I have global functions on this type, like void f( boost::variant<A,B>& var )
. I know that this can also be achieved with templates, but this is not suitable for my design.
I am very fine with this style of programming:
boost::variant<A, B> v;
f( v );
but some of the users of this library are not used to it, and since the Boost.Variant concept is hidden by a type definition, they feel like calling v.f()
.
To achieve this, I can think of two possibilities: 1) overriding from boost::variant
and 2) re-implementing boost::variant
and adding my own member functions. I am not sure whether these ideas are good or not. Can you give me some help with this please? Are there other possibilities?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
另一种可能性:使用聚合。这样您就不会直接向库的用户公开 boost.variant,从而为您提供了更多的自由来进行未来的改进,并且可以大大简化一些调试任务。
一般建议:
聚合不像继承那样紧密耦合,因此默认情况下更好,除非您知道明确希望将对象实例传递给仅采用变体的现有函数的用例。甚至比基类的设计也应该考虑到继承。
针对您的问题进行聚合的示例:
据我了解,自由函数已经存在,并且有一个变体。只需使用变体的唯一数据成员定义一个类,并提供公共成员函数,这些函数除了使用成员变体调用已经存在的自由函数之外什么也不做,就像
使用这种方法,您可以抽象出您正在使用 boost.variant 的事实您的实现(您已经通过库用户的 typedef 完成了),让您可以自由地稍后更改它(为了优化或功能扩展或其他),您可以决定使值不可变,有更简单的调试方法访问您的算法等。
聚合的缺点是您不能只将包装器传递给 static_visitor,但由于您的用户不知道存在变体,并且您知道简单地传递成员变量,我认为这里没有什么大问题。
最后吐槽一下:
C++ 不是 Java。您需要修复库的用户...
您想要的是 C# 扩展方法; C++ 中不存在这样的东西。但是,我不会重新实现/实现复制 boost.variant(维护负担),并且我不会继承它。尽可能使用聚合。
Another possibility: Use aggregation. Then you do not directly expose the boost.variant to the users of the library, giving you way more freedom for future improvements, and may simplify some debugging tasks by a significant amount.
General Advice:
Aggregation is less tightly coupled than inheritance, therefore better by default, except you know a use-case where you explicitly want to pass your object instance to already existing functions only taking variants. And even than the base class should have been designed with inheritance in mind.
Example for Aggregation for Your Problem:
As far as I understand it, the free functions already exist, and take a variant. Just define a class with the sole data member of the variant, and provide public member functions which do nothing but invoke the already existing free functions with the member variant, like
Using this approach you abstract away the fact that you are using boost.variant for your implementation (which you already do through a typedef for the library's users), giving you the freedom of later changing that (for optimization or feature extensions or whatever), you can decide to make the values immutable, have a more simple approach to debug accesses to your algorithms, etc. etc..
The disadvantage with the aggregation is that you cannot just pass the wrapper to a static_visitor, but as your users shall not know that there is a variant, and you know to simply pass the member variable, I do not see a big issue here.
Final rant:
C++ is not Java. You need to fix the users of the library...
What you would like to have are C# extension methods; such things do not exist in C++. However, I would not reimplement/implementation-copy boost.variant (maintenance burden), and I would not inherit from it. Use aggregation where possible.
我将从 boost::variant 派生。只要您不向类添加数据成员,也不添加虚函数,那就应该没问题。 (你也许可以做到其中一些,但我认为事情有点不确定)。无论如何,这对我来说似乎很有效。
I'd derive from boost::variant. That should be fine so long as you dont add data members to the class, and don't add virtual functions. (You may be able to do some of those but things are a little more iffy I think). Anyway this seems to work OK for me.