【问题标题】:Evaluate any type or function using templates使用模板评估任何类型或函数
【发布时间】:2012-03-25 15:55:34
【问题描述】:

我把之前的所有文件都留下了,与此同时,大量的事情得到了清理,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 是代表 CElements 的特定设置的类。 GUIManager 是一个单例,它将所有调用转发到当前视图和相关元素。

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

我希望能以某种方式解决问题......

编辑2: /* 删除,因为代码无论如何都不能工作... */

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

【问题讨论】:

  • 对于所有 TCDynamicLabel&lt;T&gt; 是从 CLabel 派生的吗?
  • 您可以这样做,但仍然存在何时调用这些函数的问题。标签如何知道框架何时发生变化?
  • 如果getFPS 返回float 那么*appTime-&gt;GetFPS() 没有太大意义。我认为您的意思类似于bind(&amp;Time::GetFPS, &amp;AppTime)
  • 我称它为伪代码,因为它还没有实现,但我想用类似 C++ 的语法来表达我的想法,因为部分代码实际上已经实现(但 CDynamicLabel 类还不存在)。编辑原始帖子并添加一些额外信息

标签: c++ templates boost


【解决方案1】:

您能提供更多有关用例的详细信息吗?

AFAICT,在您提供的示例中,必须将值转换为某处的文本,以便可以将值呈现到屏幕上。是吗?

所以我可以理解处理将呈现到标签中的文本的指针或引用。然后“用户端”程序可以在创建标签后更改文本。但这确实没有定义标签如何知道它必须重新渲染文本。所以这并不理想。

我也可以理解将函数指针传递给标签。该函数将返回(指向)要呈现的一段文本。这很有用,因为该函数会执行以计算值是否已更改,并将值相应地转换为文本。

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

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

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

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

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

编辑(作为披萨的结果) 这可能是一种有用的思考方式。

解决 sme 问题的优雅方法是“接口”(如 Java、Golang 或 ...)。

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

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

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

【讨论】:

  • 不必局限于文本返回函数,我计划在最后一课中使用字符串流。无论如何,我再次编辑了原始帖子,问题发生了一些变化。感谢您的想法,他们澄清了一些事情!
  • @niktehpui - 如果有帮助,你可以 +1 我!-) 我对更智能的文本交流方式没有任何问题,但是一些愚蠢的东西,比如固定大小的静态字符数组,可能更容易开始工作。我对更智能的类的担心是垃圾收集和泄漏。
【解决方案2】:

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

#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);

【讨论】:

  • 我会记住一个很好的方法,但我想实现标签,可以使用函数提供的数据更新自己,并且能够每帧更新自己。我更新了原始帖子以清除问题。
【解决方案3】:

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

/* 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();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-09
    • 2011-02-12
    • 1970-01-01
    • 2019-10-12
    • 1970-01-01
    相关资源
    最近更新 更多