如果要调用多个成员函数,对象编辑器是一种好方法吗? [英] Is Object Editor a good approach if there are multiple member functions to call?

查看:60
本文介绍了如果要调用多个成员函数,对象编辑器是一种好方法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我经常对这样的类成员函数的顺序调用感到烦恼(忽略新用法,它是针对Qt的,但并不完全与Qt相关)

I am often annoyed by sequential calls of class member function like this (ignore new usage, it's for Qt, but it's not strictly Qt-related)

A a = new A();
a->fun1("one");
a->fun2(1, 2);
...
a->fun10("end");

我一直觉得这样的代码应该写成简单的指令,而不是项目主导的代码。

I always felt that such code should be written as simple instruction, not a project dominating lines.

来自Qt的简单示例:

auto* spinBox = new QSpinBox();
spinBox->setRange(-100, 100);
spinBox->setValue(50);
spinBox->setSingleStep(5);
newLayout->addWidget(spinBox);

但是我宁愿用简单的单行代码代替它。所以我写了这样的东西:

But I would prefer to do this in simple single line instead of that. So I have written something like this:

class {
public:
    template<class X>
    auto& operator()(X* ptr) {
        this->ptr = ptr;
        return *this;
    }

    template<class X, class R, class... Args>
    auto& operator()(R (X::* fun)(Args...), Args... args) {
        if(ptr == nullptr) {
            std::cerr << "Editor can't edit nullptr" << std::endl;
            return *this;
        }
        auto call = std::mem_fn(fun);
        call(*static_cast<X*>(ptr), args...);
        return *this;
    }

    template <class X>
    operator X*() {
        auto* result = static_cast<X*>(ptr);
        ptr = nullptr;
        return result;
    }
private:
    void *ptr = nullptr;
} EDITOR;

现在的用法是:

newLayout->addWidget(EDITOR(new QSpinBox)(&QSpinBox::setRange,-100, 100)(&QSpinBox::setValue, 50)(&QSpinBox::setSingleStep, 5));

除了类型安全之外,这是一种好方法吗? (我可以接受)

Is it good approach, except not being type-safe? (I could live with that)

---
编辑
---

另一种类型安全的方法是:

Another, type-safe approach would be:

template<class X>
class EDITOR2 {
public:
    EDITOR2(X* ptr) {
        this->ptr = ptr;
    }

    template<class R, class... Args>
    auto& operator()(R (X::* fun)(Args...), Args&&... args) {
        if(ptr == nullptr) {
            std::cerr << "Editor can't edit nullptr";
            return *this;
        }
        auto call = std::mem_fn(fun);
        call(*ptr, args...);
        return *this;
    }

    operator X*() {
        return ptr;
    }

    X *ptr;
};

使用方式:

newLayout->addWidget(EDITOR2<QSpinBox>(new QSpinBox)(&QSpinBox::setRange, -100, 100)(&QSpinBox::setValue, 50)(&QSpinBox::setSingleStep, 5));

但这需要每次重新创建编辑器对象,并添加其他使用代码。

But that requires to recreate editor object every time, and adds additional usage code.

推荐答案

这有点像流畅的界面,除了使用一堆命名函数作为构建器之外,您只需使用指向成员的指针即可。这是一种合理的方法,如果您喜欢这种事情(主要是基于观点),但是完全缺乏类型安全性是不行的。

This is kind of like a fluent interface, except rather than having a bunch of named functions to as a builder, you just use pointers to members. It's a reasonable approach, if you're into that sort of thing (primarily opinion based), but the total lack of type safety is not ok.

不管 std :: cerr 不是执行错误处理的好方法。 投掷断言

Regardless std::cerr is not a good way to do error handling. throw or assert.

您可以对其进行很多改进:

You can improve it a lot:

template <class T>
struct EditorImpl
{
    T* ptr;

    template <class F, class... Args>
    Editor& operator()(F&& f, Args&&... args)
    {
        std::invoke(std::forward<F>(f), ptr, std::forward<Args>(args)...);
        return *this;
    }

    T* yield() const {
        return ptr;
    }
};

template <class T>
EditorImpl<T> Editor(T* ptr) { return EditorImpl<T>{ptr}; }

然后您可以编写:

newLayout->addWidget(
    Editor(new QSpinBox)
    (&QSpinBox::setRange,-100, 100)
    (&QSpinBox::setValue, 50)
    (&QSpinBox::setSingleStep, 5)
    .yield());






尽管如果使用该界面可能会更好已经很流利:


Though this would probably work better if the interface was already fluent:

newLayout->addWidget(
    (new QSpinBox)
    ->range(-100, 100)
    ->value(50)
    ->singleStep(5));

但这将意味着编写一堆新的命名函数,您肯定会(可能?)

But that would imply writing a bunch of new named functions, which you're definitely (probably?) not going to do.

std :: invoke() 是C ++ 17,但可在C ++中实现11。

std::invoke() is C++17, but is implementable in C++11.

这篇关于如果要调用多个成员函数,对象编辑器是一种好方法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆