【问题标题】:C++ weird syntax spotted in Boost template parametersBoost 模板参数中发现 C++ 奇怪的语法
【发布时间】:2011-03-08 17:52:33
【问题描述】:

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

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

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

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

【问题讨论】:

  • 每个问题只问一个问题 - 如果您有两个问题要问,请分别提交两个问题。
  • 真的,对不起,我不会再这样做了
  • 您可以编辑您的问题以删除其中一个问题以将其拆分为另一个问题 - 很难这样回答,因为如果有人只知道您的一个问题的答案,他们会觉得不愿提交答案。

标签: c++ boost functor boost-function


【解决方案1】:

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

我必须承认这种语法非常 让我困惑。怎么会这样 合法的 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 实现。

但是,我想解决您的一般问题。我认为您正在努力简化几行完全可以接受的代码。通过参数化子类构造函数传递命令子类的参数没有任何问题。是否真的值得在这里尝试使用 typelist 和 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 编写一个非常通用的解决方案,许多人可以跨许多平台和编译器使用它。然而,他们并没有试图概括一个能够在统一的撤消系统中执行具有不同签名的函数的命令系统(因此,即使在最初完成调用它们并能够撤消和重新调用这些命令之后,也需要保留这些命令的状态。 - 执行它们而不在后续执行中重新指定原始状态数据)。为此,您的基于继承的方法很可能是最好和最直接的方法。

【讨论】:

  • typedef float (int, int) Command,很抱歉,不是合法的 C。正确的 C 代码应该是 typedef float Command(int, int)typedef 采用常规声明,而不是定义命名对象(即函数或变量),它使用名称作为对象类型的别名。
  • @Dale 道歉,你是对的,这在 C++ 中也是非法的。当试图用 C c; 解释 C 被参数化为什么时,这是一个草率的错误;相当于写: typedef float Command(int, int); C c.我对其进行了编辑以纠正错误。
  • @Dale 恐怕我过早地投票赞成你的评论 :) 请注意函数不是对象。
  • @Johannes:我知道形式上的函数不是对象,但我试图区分运行时实体(数据对象或函数)和编译类型实体(类型由 typedef 声明)。
猜你喜欢
  • 2011-09-13
  • 1970-01-01
  • 2016-01-20
  • 1970-01-01
  • 1970-01-01
  • 2017-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多