0

想象一下,有一个标签在创建后更新 x 次/秒。标签的文本作为格式说明符文本(ala printf)给出,格式说明符的任何参数都会在重绘时更新,因为格式说明符的参数是指向它们各自值的指针。sprintf 的任何变体都可以这样工作吗?

该代码将像这样工作:

/* client */
createLabel("Value is %f", &myFloatValue);

我还没有完全想出一个方法来做到这一点,有没有人有任何想法?我想人们可以解析格式文本,检索指针(和类型),并将它们作为某个对象存储在列表中,稍后您可以在其中重新打印文本并可能将格式委托给对象本身,只传递一个文本缓冲区。 . 嗯

顺便说一句,接口是 C,但主机是 C++。

好的,我有一个“工作”原型,但它主要是用汇编程序编写的。无论如何,它演示了 api 的假定用途。任何人都可以看到一种可移植的方式来做到这一点/对实施​​有更好的想法吗?它很大,所以我把它贴在 pastebin 上:http: //pastebin.com/H8ZpWb4u

4

3 回答 3

0

好的,我突然有了一个想法.. stringstream + 模板化多态性。我最终在 5 分钟内用 C++ 编写了这个东西,至少这是一个巨大的改进。

#include <string>
#include <iostream>
#include <vector>
#include <sstream>

class CBaseValue 
{
public:
    virtual void toString(std::stringstream & buf) = 0;
};

template< typename T >
    class CValue : public CBaseValue
    {
        typedef T type;
        typedef T * ptr_type;
        type * val;

    public:
        CValue(void * val) 
        {
            this->val = reinterpret_cast<ptr_type>(val);
        }

        CValue(type * val) : val(val) {}

        virtual void toString(std::stringstream & buf) {
            buf << *val;
        }
    };

class CLabel 
{

    std::stringstream ss;
    std::vector<CBaseValue *> valueList;
    std::string format;

public:
    CLabel() {};
    void reset() {
        format.clear();
        ss.str("");
        for(unsigned i = 0; i < valueList.size(); i++) {
            delete valueList[i];
        }
        valueList.clear();
    }
    void setFormat(const char * fmt, ...) {

        reset();
        format = fmt;
        va_list args;
        va_start(args, fmt);

        for(unsigned i = 0; i < format.size(); ++i) {
            if(format[i] == '%') {
                ++i;
                switch(fmt[i])
                {
                case 'd':
                    valueList.push_back(new CValue<unsigned int>( va_arg(args, void *) ));
                    break;
                case 'f':
                    valueList.push_back(new CValue<float>( va_arg(args, void *) ));
                    break;
                }
            }
        }
        va_end(args);

    }

    std::string get() {
        ss.str("");
        unsigned count(0);
        for(unsigned i = 0; i < format.size(); i++) {
            if(format[i] == '%') {
                i++; // ignore type specifiers, already polymorphically solved
                valueList[count++]->toString(ss);
            } else {
                ss << format[i];
            }
        }
        return ss.str();
    }
    ~CLabel() {
        reset();
    }
};


int main() {

    int test = 2;
    float val = 3.14f;

    CLabel myLabel;
    myLabel.setFormat("Stringstream test, float: %f, and an int: %d \n", &val, &test);
    std::cout << myLabel.get();
    test = 3;
    std::cout << myLabel.get();

    system("pause");
}
于 2013-07-30T22:28:24.420 回答
0

因此,您的createLabel界面将存储格式字符串以及您希望在字符串中显示的变量的地址。然后只需使用标准旧sprintf来重新格式化文本。请注意这些指向数据的指针,并确保在必要时使它们无效。

我不确定问题是什么。你还在寻找什么? sprintf能够做你想做的事,但你必须自己跟踪格式字符串和变量地址。

于 2013-07-29T20:09:54.530 回答
0

std::bind你可以用or做一些相对简单的事情boost::bind。我将把它作为如何在此之上按摩 C 接口的练习。

#include <functional>

int main() {
  int test = 2;
  float val = 3.14f;

  std::function<int()> label = std::bind(
      printf,
      "Stringstream test, float: %f, and an int: %d \n",
      std::ref(val),
      std::ref(test));

  label();
  test = 3;
  label();
}
于 2013-07-30T22:57:39.397 回答