这个C++语法应该如何阅读?

6

我可能很蠢,但是我刚刚看到了这个C++语法,却完全弄不清它在做什么:

(*x)(&a, b, c);

希望能尽快得到答复。


1
你可能会发现http://www.cdecl.org/很有用。 - user597225
@Adam12:那不是一个声明,因此cdecl.org帮不上什么忙。 - David Rodríguez - dribeas
不错的链接,尽管我按照上面所写的内容粘贴进去,但它返回了一个“语法错误”。 - Ed King
你说得对,这个特定的代码片段可能用不上,但有时候还是很有用的。 - user597225
@EdKing:在C++中,任何对象的类型都是至关重要的。当发布代码时,最好让代码片段包含所有使用对象的类型。 - Martin York
9个回答

20

这里有许多可能性:一切取决于所有实体的类型:xabc。在C++中,您甚至可以重载逗号运算符。

但我只会关注 x,看看事情如何发展。然而,如果考虑所有组合,实际答案将会太长。

(*x)(&a, b, c);

这里的x可以是以下之一:

  • 函数指针
  • 函数对象的指针。
  • 迭代器,解引用后返回函数指针或函数对象。
  • (底部还有一个,但被上一个部分遮盖了!)

然后您会传递三个参数来调用它。

以下是一些示例,假设所有其他实体(abc)均为int

  • 一个假设

 int a,b,c; //FIXED as per the assumption
  • 函数指针

  •  void f(int *,int, int);
     auto *x = f;
     (*x)(&a,b,c); //x is function pointer 
     x(&a,b,c);    //works fine, even without (*x)
    
  • 函数对象

  • struct X { void operator()(int*,int,int); };
    
    X y, *x = &y;
    (*x)(&a,b,c);  //x is pointer to function object
    
  • 迭代器

  • std::list<std::function<void(int*,int,int)> l {X(), f};
    auto x = l.begin();  //x is an iterator
    (*x)(&a,b,c);  //(*x) is function object
    ++x;
    (*x)(&a,b,c);  //(*x) is function object (still!)
    
    //OR
    std::list<void(int*,int,int)> l {f};
    auto x = l.begin();  //x is an iterator
    (*x)(&a,b,c);  //(*x) is function pointer!
    

    正如 @David 在评论中所说:

    然而,还有第四种可能性:x 可能是某个类的实例,该类重载运算符*以返回函数指针或函数对象。

    这是正确的,但我认为这种可能性部分地被迭代器所涵盖,或者至少迭代器的示例给了你足够的提示,让你自己找出答案。:-)

    希望这可以帮到你。


    1
    @Downvoter:请指明原因? - Nawaz
    3
    关于指向函数对象的指针,这是一个很好的观点。当然,如果 x 具有类类型,并且具有重载的一元 * 运算符,则可能存在更多可能性。更不用说如果 b 具有用户定义类型,并且有逗号运算符的重载。通过巧妙地使用重载,这些可能性就无穷无尽了。 - James Kanze
    @Nawaz 我也很好奇原因。这个答案是正确的。 - user529758
    我不是一个downvoter。事实上,我是一个upvoter。但是,还有第四种可能性:x可能是某个类的实例,该类重载了operator*以返回函数指针或函数对象。 - David Hammen
    1
    @DavidHammen:是的,那是另一种可能性,但这一点部分迭代器所覆盖? - Nawaz
    1
    不错的帖子。除非有更好的帖子出现,我认为这应该被视为原始问题的答案。 - luis.espinal

    7
    似乎x是一个函数指针。如果是这种情况,那么这意味着:
    1. 解引用x以获得函数类型的表达式;

    2. 使用参数addressof abc调用该函数。

    此外,请注意*(解引用)和()运算符在x周围是多余的;你可以写成
    x(&a, b, c);
    

    如果x是函数指针,同样适用。


    第二个踩的原因是什么? - user529758
    我猜测装饰x()*是让我感到困惑的原因,特别是如果它们不是必需的,就像你所说的那样。这是一个函数指针。谢谢。 - Ed King
    1
    第三个踩的原因是什么?哦,还没有第三个踩(但你永远不知道 :))。开玩笑了,答案是正确的,尽管它假设 x 是一个函数指针,但它也可能是一个指向函数对象的指针(在这种情况下,括号和 * 都不是多余的)。但我没有踩。 - David Rodríguez - dribeas
    @DavidRodríguez-dribeas 说得好!正如我所写的,我假设 x 是一个函数指针。另外,还有一个条件语句说“如果x是一个函数指针”,所以这应该没问题(如果我在逻辑上没有失败的话:P) - user529758

    3
    不知道符号的定义是什么,无法百分之百确定,但我怀疑这是一个函数调用。(假设x是指向函数的指针;如果x具有类类型,则取决于类中一元*的重载。)因此,(*x)解引用指针,并在逻辑上是一个函数;鉴于此,其余部分应该很明显。(请注意,在大多数情况下,函数在形式上会衰减为指向该函数的指针,并且您通过指向函数的指针进行调用。因此,如果x是函数指针,则(*x)和x在编译器看来是相同的。然而,对于人类读者来说并非如此,并且大多数人会欣赏被告知调用是间接的。)

    2
    以下是使用operator()的示例,它可以产生相同的签名。
    #include <iostream>
    using namespace std;
    
    struct sample {
        void operator()(int* a, int b, int c) {
            *a = b = c;
            return;
        }
    };
    
    int main() {
        sample* x;
        int a = 1, b = 1, c = 1;
        (*x)(&a, b, c);
        return 0;
    }
    

    1
    这很可能是通过一个函数指针调用的函数。更常规的语法如下所示:
    x(&a, b, c);
    

    x指向一个接受三个参数的函数。调用表达式对指针进行解引用,并将三个参数传递给指针所指向的函数。

    另一种可能是x是一个指向对象的指针,该对象定义了一个三参数运算符()的重载。要知道它是哪一个,需要提供更多的上下文。


    1
    更传统的语法是为了谁而存在?说你的意思,做你所说的,即使语言中的某些奥秘规则不要求这样做。如果你有一个指针,并且想使用它所指向的内容,请对其进行解引用。 - James Kanze
    在 ANSI C 标准时代,语言设计师意识到函数指针是一种特殊的指针,并且应该有一个特殊的语法。他们使显式解引用成为可选项。显式解引用已经保留下来以保持向后兼容性,但据我所记,在 C 中至少被忽略了。 - Sergey Kalinichenko
    1
    在B语言(C的前身)中,没有类型,而()运算符将其参数视为函数。 C遵循了这一做法,但它是一个相当少用的特性,至少在我看到的C中是如此。 在C中,指向函数的指针很少见,好的程序员认为使用显式语法来引起注意间接调用的事实非常重要。 在C ++中,您不需要显式解引用的事实是出于与C兼容的原因,但是再次强调,好的C ++程序员不使用它(除了在模板中偶然使用)。 - James Kanze

    1

    x 可能是指向函数的指针,或者指向函数指针的指针。


    1

    这是通过函数指针调用函数。

    使用提供的参数调用由指针“x”指向的函数。

    这个参考可能会有帮助:C++函数指针教程


    0

    看起来x是一个指向函数指针的指针,或者是一个指向仿函数的指针。&a、b、c是函数调用的参数列表。


    0

    它将参数 &a, b, c 传递给一个由 *x 指向的函数


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接