c++ - 在语句持续时间内自动换行值

标签 c++ c++11

是否可以自动将一个值包装在一个生命周期跨越整个语句的临时值中?


最初我希望我的问题的解决方案或替代方案会出现 while writing the details对于这个问题,不幸的是那没有发生,所以......

我有一个抽象基类 Logger,它提供了一个类似流的接口(interface)来生成日志语句。给定此类的实例 logger,我希望以下情况成为可能:

logger << "Option " << variable << " is " << 42;

与常规流不同,它只是从所有组件(上面示例中的 4 个组件)生成一个字符串,我想生成一个 Statement 类的实例,它管理所有组件的链表语句的组成部分。然后通过纯虚方法将整个语句传递给派生自 Logger 的类,该类可以遍历语句的所有组件并对它们执行任何操作,包括获取有关它们的类型的信息、检索它们的值,或将它们转换为字符串。

棘手的一点:我想在没有动态内存分配的情况下执行上述操作。这意味着语句的每个组件都必须由一个临时类型包装,该临时类型将组件链接到语句范围内的可遍历列表!

I posted a working example on ideone ,有一个问题:每个组件都需要通过函数调用来包装,以便生成临时类型的实例。因此,日志语句最终看起来像这样:

logger << wrap("Option ") << wrap(variable) << wrap(" is ") << wrap(42);

到目前为止,我试图摆脱 wrap 函数(例如,为组件使用隐式转换构造函数)的所有尝试都失败了,因此出现了这个问题。


如何将日志语句的组件自动包装在它们的组件类型中(例如,使用组件的转换构造函数),而不需要显式调用包装函数?

或者,对于实现相同效果的其他方法的建议,我将不胜感激,即允许在从记录器派生的类中迭代日志语句的组件,而无需动态内存分配。


引用:ideone上的完整代码:

#include <iostream>
#include <sstream>

struct Statement;
struct Logger;
struct ComponentBase;

//------------------------------------------------------------------------------

struct ComponentBase {
    mutable ComponentBase *next;
    ComponentBase() : next(nullptr) { }
    virtual std::string toString() = 0;
};

template <typename T>
struct Component : ComponentBase {
    T value;
    Component(T value) : value(value) { }
    ~Component() { }
    virtual std::string toString() {
        std::stringstream ss;
        ss << value;
        return ss.str();
    }
};

struct ComponentIterator {
    ComponentBase *ptr;
    ComponentIterator(ComponentBase *ptr) : ptr(ptr) { }
    ComponentBase &operator*() { return *ptr; }
    void operator++() { ptr = ptr->next; }
    bool operator!=(ComponentIterator &other) { return (ptr != other.ptr); }
};

//------------------------------------------------------------------------------

struct Statement {
    Logger *logger;
    ComponentBase *front;
    ComponentBase *back;
    ComponentIterator begin() { return front; }
    ComponentIterator end() { return nullptr; }

    template <typename T>
    Statement(Logger &logger, Component<T> &component)
    : logger(&logger), front(&component), back(&component) { }
    ~Statement();

    template <typename T>
    Statement &operator<<(Component<T> &&component) {
        back->next = &component;
        back = &component;
        return *this;
    }
};

//------------------------------------------------------------------------------

struct Logger {
    template <typename T>
    Statement operator<<(Component<T> &&component) {
        return {*this, component};
    }

    virtual void log(Statement &statement) = 0;
};

Statement::~Statement() {
    logger->log(*this);
}

//------------------------------------------------------------------------------

template <typename T>
Component<T const &> wrap(T const &value) {
    return value;
}
template <size_t N>
Component<char const *> wrap(char const (&value)[N]) {
    return value;
}

//------------------------------------------------------------------------------

struct MyLogger : public Logger {
    virtual void log(Statement &statement) override {
        for(auto &&component : statement) {
            std::cout << component.toString();
        }
        std::cout << std::endl;
    }
};

int main() {
    std::string variable = "string";
    MyLogger logger;
    logger << wrap("Option ") << wrap(variable) << wrap(" is ") << wrap(42);
}

最佳答案

我有一些疯狂但可行的解决方案。

像这样实现组件,您将摆脱整个代码中的模板:

struct Component 
{
    mutable Component *next;
    typedef std::function<std::string()> ToStringFunction;
    ToStringFunction toString; // <-- 1

    template<typename T>
    Component(const T& value) 
        : next(nullptr),
        toString(nullptr)
    {
        toString = [&value](){
            std::stringstream ss;
            ss << value;
            return ss.str();
        };
    }
};

其中 (1) 是知道该做什么的函数。这个成员std::function是一个优化空间。

剩下的代码应该是这样的:

struct ComponentIterator {
    Component *ptr;
    ComponentIterator(Component *ptr) : ptr(ptr) { }
    Component &operator*() { return *ptr; }
    void operator++() { ptr = ptr->next; }
    bool operator!=(ComponentIterator &other) { return (ptr != other.ptr); }
};

//------------------------------------------------------------------------------

struct Statement {
    Logger *logger;
    Component *front;
    Component *back;
    ComponentIterator begin() { return front; }
    ComponentIterator end() { return nullptr; }

    Statement(Logger &logger, Component &component)
        : logger(&logger), front(&component), back(&component) { }
    ~Statement();

    Statement &operator<<(Component &&component) {
        back->next = &component;
        back = &component;
        return *this;
    }
};

//------------------------------------------------------------------------------

struct Logger {
    Statement operator<<(Component &&component) {
        return{ *this, component };
    }

    virtual void log(Statement &statement) = 0;
};

Statement::~Statement() {
    logger->log(*this);
}

//------------------------------------------------------------------------------

struct MyLogger : public Logger {
    virtual void log(Statement &statement) override {
        for (auto &&component : statement) {
            std::cout << component.toString();
        }
        std::cout << std::endl;
    }
};

int main() {
    std::string variable = "string";
    MyLogger logger;
    //logger << wrap("Option ") << wrap(variable) << wrap(" is ") << wrap(42);
    logger << 42;
    logger << variable << " is " << 42;
    logger << "Option " << variable << " is " << 42;
}

这将打印:

42
string is 42
Option string is 42


更新 正如 dyp 建议的那样,这里是不带 lambda 的 Component 结构的替代实现:

struct Component
{
    mutable Component *next;
    void* value;
    std::string toString(){
        return _toString(this);
    }

    template<typename T>
    Component(const T& inValue)
        : next(nullptr),
        value((void*)&inValue),
        _toString(toStringHelper<T>)
    {}
private:
    typedef std::string(*ToStringFunction)(Component*);
    ToStringFunction _toString;

    template<typename T>
    static std::string toStringHelper(Component* component)
    {
        const T& value = *(T*)component->value;
        std::stringstream ss;
        ss << value;
        return ss.str();
    }
};

关于c++ - 在语句持续时间内自动换行值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37135497/

相关文章:

c++ - 在运行时设置 vector 的 vector 大小

c++ - 返回元组时如何转移 unique_ptr 的所有权?

c++ - 'stol' 使用 Visual Studio 而不是 gcc 引发的异常

c++ - Eclipse CDT 无法解析 std:array,std::vector 工作正常

c++ - 如何设置 [ ZeroMQ ] 以便在 Visual Studio 2015 Enterprise 中使用?

c++ - 如果我的类是文字类,那么将我的类的对象声明为 constexpr 是否多余?

c++ - 无法隐式初始化 std::function

c++ - 标准与显式自动推导变量声明

c++ - 复制和移动构造函数之间的效率差异

c++ - 可变的不区分大小写的字符串比较性能