在不继承的情况下回收成员功能

Recycling member functionality without inheritance

本文关键字:成员 功能 情况下 继承      更新时间:2023-10-16

维基百科上有一个有趣的Properties模板。

这个模板提供了一些有趣的东西,因为它允许围绕成员访问提供逻辑。在此基础上,我们可以很容易地构建这样的东西:

struct Ranged { 
  ranged_property<float,0,1> unit_property; 
}; 

其中unit_property的范围强制在[0,1]内。

我们如何提供类似的功能取决于托管类的成员?例如:

struct AdjustableRanged { 
  float max; 
  ranged_property<float,0,max> influenceable_property; 
};

其中influenceable_property的范围受max的值的影响。请记住,目标是让这种模板在许多截然不同的类中循环使用。相关的概念是mixin和decorator。

它可以用宏来完成。。。但我觉得必须有一个更好、更惯用的C++解决方案。


编辑后添加:我认为这可以通过在ranged_property模板中保存对成员的引用来完成。。。但这似乎完全是在浪费空间,因为这实际上是一个恒定值ETA;事实上,const引用可能会达到目的,但我需要进行调查。

根据我们在评论中的讨论,似乎可以通过这样的指向成员模板参数的指针来实现功能(但请参阅下面的注意事项):

#include <iostream>
template<typename C, typename T, T C::*m>
struct PrintMember {
    C& obj;
    PrintMember(C& obj) : obj(obj) {};
    void print() { std::cout << "Member of containing class: " << obj.*m << std::endl; };
};
struct TestClass {
    int data;
    PrintMember<TestClass, int, &TestClass::data> pm;
    TestClass() : pm(*this){};
};
int main()
{
    TestClass tc;
    tc.data = 5;
    tc.pm.print();
}

这仅表明可以访问包含对象的成员。有一些事情这种方法不能解决:

  • 如果您真的只想访问一个成员,那就不值得了,因为您必须在PrintMember成员中保存对*this的引用,才能取消引用指向成员的指针。因此,它实际上并不能解决必须存储引用的问题。您也可以在构造函数中传递对成员变量本身的引用。但是,如果您需要访问多个成员,这允许您只存储一个引用(到*this),并且仍然可以访问所有引用。

  • 指定PrintMember的模板参数并在构造函数中使用*this初始化PrintMember成员变量是乏味的。也许,一些巧妙的模板论点推导可以在这里有所帮助,但我还没有尝试过,我甚至不确定它会变得更简单。。。

在某些特殊情况下,可能有一些肮脏的方法可以在不显式保存的情况下访问封闭类的"this"指针,比如在这个答案中使用offsetof的答案,但我的感觉告诉我,你想要便携且不那么脆的东西。。。