8

我正在查看 Boost 中的“Function”类文档,并偶然发现了这一点:

boost::function<float (int x, int y)> f;

我必须承认这种语法对我来说非常混乱。这怎么可能是合法的 C++ ?

引擎盖下有什么技巧吗?这种语法是否记录在任何地方?

4

1 回答 1

9

[编辑] 这是对作者原始的、未经编辑的问题的回答,实际上是两个问题。

我必须承认这种语法对我来说非常混乱。这怎么可能是合法的 C++ ?:) 引擎盖下有什么技巧吗?这种语法是否记录在任何地方?

这是完全合法的,实际上并不太复杂。

template <class T>
class C
{
public:
    T* function_pointer;
};

void fn(int x)
{
    cout << x << endl;
}

int main(int argc, char** argv)
{
    C<void (int x)> c;
    c.function_pointer = &fn;
    c.function_pointer(123); // outputs x
}

这与做的事情基本相同:

typedef void Function(int);
C<Function> c;

这种类型不仅适用于 C++,它同样适用于 C(实际类型 C 被参数化为)。这里的模板魔法在这里采用类似于 Function typedef 的东西,并且能够检测返回值和参数的类型。在这里解释太冗长了, boost::function 在 boost 中使用了许多函数特征元模板来检索该信息。如果你真的想花时间学习这个,你应该试着理解从 Boost.Type Traits 中的 boost::function_traits 开始的 boost 实现。

但是,我想解决您的一般问题。我认为您正在努力简化几行完全可以接受的代码。通过参数化子类构造函数传递命令子类的参数并没有错。是否真的值得在这里尝试涉及类型列表和 boost::function-like 解决方案,从而显着增加编译时间和代码复杂性,仅仅是为了这个?

如果您想进一步减少它,只需编写一个执行函数,该函数将执行任何命令子类并将其添加到撤消堆栈等:

typedef boost::shared_ptr<Command> CommandPtr;

void execute(const CommandPtr& cmd)
{
    cmd->execute();
    // add command to undo stack or whatever else you want to do
}

// The client can simply write something like this:
execute(CommandPtr(new CmdAdd(some_value) );

我真的认为试图让它变得更复杂的权衡是不值得的。boost 作者想为 boost::function 编写一个非常通用的解决方案,许多人可以跨许多平台和编译器使用它。然而,他们并没有试图概括一个能够在统一的撤消系统中执行具有不同签名的函数的命令系统(因此,即使在最初完成调用它们并能够撤消和重新调用这些命令之后,也需要保留这些命令的状态。 - 执行它们而不在后续执行中重新指定原始状态数据)。为此,您的基于继承的方法很可能是最好和最直接的方法。

于 2010-06-27T02:09:17.497 回答