【问题标题】:Why Is Ampersand Necessary For Referencing The Call Operator为什么引用呼叫操作员需要与号
【发布时间】:2015-12-21 17:23:57
【问题描述】:

我认为 C++ 规范说,在引用函数时,函数前面的 & 符号是不必要的,即

void bar();
void foo(void(*bar)());

foo(bar);
foo(&bar);  // Same as above.

但是,我发现了一个不正确的案例。我试图对 lambda(仅单个参数)进行模板特化,以便我可以访问 lambda 的返回参数和输入参数的类型。

// The ampersand in front of 'Fn::operator()' is necessary to make
// this code work.
template <typename Lambda>
struct Signature : public Signature<decltype(&Fn::operator())> {};

template <typename ClassT, typename RetT, typename ArgT>
struct Signature<RetT(ClassT::*)(ArgT) const> {
  using ReturnType = RetT;
  using ArgumentType = ArgT;
};

没有和号,clang 抱怨

error: call to non-static member function without an object argument
struct Signature : public Signature<decltype(Fn::operator())> {};
                                             ~~~~^~~~~~~~

我让代码工作,但我想了解它为什么工作。为什么这里需要 & 符号?

【问题讨论】:

  • 简单的答案是成员函数不是常规函数。也许 Bjarne 认为函数和函数指针的奇怪细节(例如,当你调用一个函数名称时衰减为指针)是一个错误,并且使成员函数及其指针的行为有所不同。不过,我不知道这种行为不同的真正原因。
  • 成员函数释放函数的规则不同。指向成员的指针与普通函数指针不同
  • 请注意,您的模板魔法不会在任何地方都起作用(我在想例如使用 const 类的地方。最好使用 std 类型的特征,如 std::result_of .
  • @Rubenvb,感谢您建议std::result_of。有没有类似的获取参数类型的方法?
  • @kirakun 我相信你需要 Boost:boost.org/doc/libs/1_60_0/libs/type_traits/doc/html/…

标签: c++ templates


【解决方案1】:

要获取成员函数的地址,您必须始终在其前面加上 &amp;(与号)。这不仅适用于模板和/或 lambda,而且适用于 C++ 中的任何成员函数。

至于为什么,我们只能推测。但这就是 C++ 一直以来的样子。也许 C 兼容性是允许省略 &amp; 的免费函数的唯一原因。

【讨论】:

    【解决方案2】:

    指向函数的指针和指向成员函数的指针是不同的野兽。虽然函数衰减为指向函数的指针,但对于成员函数或成员对象而言,情况并非如此。虽然有一个标准的指针转换函数,但成员函数或成员对象没有类似的东西。当您想获得指向成员的指针时,您总是需要使用&amp;

    我不知道确切的推理,但我怀疑需要地址运算符以避免有时出现在函数中的错误,例如:

    int f();
    // ...
    if (f) { // always true
    }
    

    虽然在不破坏 C 兼容性的情况下无法删除从函数到函数指针的隐式转换,但在引入成员和指向成员的指针时没有类似的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-06
      • 2012-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-08
      • 1970-01-01
      相关资源
      最近更新 更多