使用模板评估任何类型或函数

Evaluate any type or function using templates

本文关键字:类型 函数 任何 评估      更新时间:2023-10-16

我留下了以前为文档问题撰写的所有内容,同时清除了大量内容,EDIT2是当前状态:

我目前正在为我的大学课程开发一个简单的GUI系统,我提出了一个简单想法和问题。我在想一种动态标签:

我认为,如果一个"动态"标签类可以简单地绑定每种函数或指针,在每帧自动打印它们,那就太好了,而不是在每帧都向"静态"标签传递一个值/字符串。

这里有一些伪代码要演示,我想实现的是:

/* OLD WAY */
// called on initialization:
CView* pView = new CView();
CLabel* pLabel = new CLabel(10,20,"TEST");
pView->Attach(pLabel);
GUIManager->SetActive(pView);
// ...
// called every frame somewhere:
pLabel->SetText(AppTime->GetFPS()); //(AppTime is a singelton with time informations)
/* NEW WAY */
// called on initialization:
CView* pView = new CView();
//(the return type of GetFPS is float)
CDynamicLabel<float>* pDLabel = new DynamicLabel<float>(10,20, *AppTime->GetFPS());
// not only functions or member functions, this should also be possible
CDynamicLabel<int>* pDLabel2 = new DynamicLabel<int>(20,20, ptrToSomeInteger);

因此,我认为必须有一种方法将C++模板系统和boost::bind结合起来,才能获得我想要的功能,但我不知道如何实现。我希望有人能给我一些关于如何实现这一目标的提示。也许还有另一种更常见的方法来获得这种功能。

编辑:为了澄清一些问题,与动态标签相关的C++代码尚未实现。我仍在努力寻找实现它的完美方法,但要澄清我当前类层次结构的一些问题:

我有一个虚拟类CElement,每个GUIElement都派生自它。有用于渲染、更新(以经过的时间为参数)的虚拟函数,以及以事件为参数的OnEvent函数。此外,通用可见性函数在CElement类中实现。CView是一个类,它表示特定的CE元素设置。GUIManager是一个Singleton,它将所有调用转发到当前视图和相关元素。

我的基本想法是,因为GUI系统是游戏的一部分,所以如果有一种通用的方法来实现自我更新标签,而不是为某个标签编写另一个派生类,只需将fps打印到屏幕上或类似的内容,那么更新函数在每一帧都会被调用。

我希望事情能以某种方式澄清。。。

第2版:/*已删除,因为代码无法正常工作…*/

第3版:一切都正常了,我使用了boost::function和boost::bind,并编写了一个模板,现在可以做我想做的一切。。。

您能提供更多用例的细节吗?

AFAICT,在您提供的示例中,必须将值转换为某个位置的文本,以便将值呈现在屏幕上。对

因此,我可以理解将指针或引用交给将被呈现到标签中的文本。然后,"用户端"程序可以在创建标签后更改文本。但这确实留下了未定义的标签如何知道它必须重新呈现文本。所以这并不理想。

我还可以理解将函数指针传递到标签。函数将返回(指向)要呈现的文本片段。这很有用,因为执行该函数可以确定值是否发生了更改,并相应地将值转换为文本。

同样,标签如何知道它需要调用函数也是未定义的。但假设尝试的标签可以解决这个问题,这是完全相同的问题,所以我认为这已经解决了。

这似乎是唯一必要的情况。使用它似乎其他一切都是可行的。因此,标签可以在函数上模板化,这会隐藏类型,而不是值的数据类型,这是无关紧要的,因为无论如何都必须将其转换为文本。

这样做的另一个优点是该功能可以确保格式看起来正确。我喜欢像帧时间这样的东西,将其渲染为固定宽度的场,如果它缩小和加宽,则会很难看。

它的概括是一个模板类,它具有用于"用户端"程序设置和更新值的特定类型的访问器,以及一个返回要呈现的字符串的固定函数。

摘要:返回文本字符串的函数上的模板,或具有定义良好的返回文本字符串函数的类上的模板。

编辑(由于披萨)这可能是一个有益的思考方式

中小企业问题的一个优雅的解决方案是"接口"(如Java、Golang或…)

在这种情况下,接口只需要一个无参数的函数,该函数返回(在我的示例中)一个文本字符串。它是交给标签的接口。

接口需要嵌入一个值、引用或指向实现该值的对象(类实例或POD)的指针,并且该类或POD需要有一种方法来提供文本字符串。

实现该值的类或POD被接口从标签中隐藏。

我不知道你的类层次结构,但这里有一个通用的想法:

#include <type_traits>
struct CLabel { virtual ~CLabel() { } /* ... */ };
template <typename T>
struct DynamicLabel : CLabel
{
    DynamicLabel(T);
    // ...
};
template <typename T>
CLabel * LabelMaker(T x)
{
    return new DynamicLabel<typename std::remove_reference<T>::type>(x);
}

现在你可以使用:

CLabel * p = LabelMaker(12U), * q = LabelMaker(1.5L);

对于所有想做类似事情的人来说,这里是我最后一个简单的测试代码,它说明了功能:

/* DynamicLabel.hpp */
template <class T> class CDynamicLabel : public CElement
{    
public:
    CDynamicLabel(void) {}
    CDynamicLabel(boost::function0<T> f) : m_f(f) {}
    void TestCall(void) const { cout << m_f(); }
private:
    boost::function0<T> m_f;
};
/* Test Code in Main (MEMFUNC is a Macro to simplify binding and AppTime is a definition to simplify the CAppTime-Singleton calls) */
CDynamicLabel<float> TestDL(MEMFUNC(&CAppTime::GetLastGPUDelta, AppTime));
TestDL.TestCall();