【问题标题】:Understanding complex typedef expressions [duplicate]理解复杂的 typedef 表达式
【发布时间】:2017-04-07 14:12:18
【问题描述】:

我想知道这个表达是什么意思??

typedef bool (*compareShapes)(const Shape* s1, const Shape* s2);

Shape 是一个类。

【问题讨论】:

  • 不是*compareShapes吗?在这种情况下,它是一个函数指针 typedef。
  • 看起来很像一个函数指针。这意味着可以将任何按值采用一种形状,按指针采用一种形状的函数分配给 compareShapes。您可以通过这种方式实现通用算法。有关使用它的示例,请参见 qsort。另一种方法是模板,请参阅 std::sort 以了解如何使用模板完成相同的想法
  • 您可能想知道为什么它是一个指向函数的指针 声明而不是函数本身。原因是函数不能通过值传递和返回;你只能用指向它的指针来做到这一点。

标签: c++ c++11


【解决方案1】:

您应该使用 using 语句。它使相同的声明更易于阅读:

using compareShapes = bool(*)(const Shape*, const Shape*);

现在看到了吗?类型在等号之后。它是一个指向函数类型的指针。

也可以这样声明:

// function pointer type --v----------------------------------------------------v
using compareShapes =      std::add_pointer_t< bool(const Shape*, const Shape*) >;
//                    function signature  -----^------------------------------^

函数签名是这样组成的:

<return-type>( <arguments...> )

当你在其中添加指针时,它看起来像这样:

<return-type>(*)( <arguments...> )

如果你在此处添加指针名称或类型名称,请在星号之后添加:

<return-type>(*typeOrPointerName)( <arguments...> )

【讨论】:

  • 很好的说明!
  • 也许我的观点不受欢迎,但我发现 typedef 在很多情况下更容易阅读,包括这个。
  • 也许我是个老屁,但我的反应是“天哪,不是另一种写我现在必须记住的同样该死的东西的方式”。跨度>
  • 虽然我想“等等,有一种旧方法?呃,那太丑了。很高兴新方法存在”
  • 问题是“我正在阅读代码并发现了这个,它是什么?”,为什么评分最高的答案是“你应该这样做”? o.O
【解决方案2】:

嗯,它是一个 typedef,所以有两部分 - 类型和为其定义的新名称。

第一部分是类型:

bool (*)(const Shape* s1, const Shape* s2);

这是一个指向函数的指针,接受两个指向 const-Shape 参数的指针,并返回 bool。

第二部分是类型的名称:compareShapes。诚然,函数指针类型定义很难阅读,但这部分是因为函数指针语法不经常使用。

因此,例如,我可以编写任意数量的兼容函数:

bool identical(const Shape *a, const Shape *b);
bool strictlyContained(const Shape *a, const Shape *b);
bool topologicallyEquivalent(const Shape *a, const Shape *b);

这告诉我a 是否与b 相同,或者完全在b 内部,或者ab 是否具有相同数量的孔。

然后,我可以编写适用于任何比较的代码,并选择以后使用的代码,例如:

compareShapes cmp;
if (shouldUseIdentityComparison()) {
  cmp = &identical;
} else if (shouldUseInsideComparison()) {
  cmp = &strictlyContained;
} else {
  cmp = &topologicallyEquivalent;
// ...
if (cmp(a,b)) {
    // they're equal, for whichever comparison we chose above
}

在现代代码中可能更常见的是编写模板,采用任意比较器类型(如std::sort),或者编写采用std::function&lt;bool(const Shape*, const Shape*)&gt; 的非模板函数,这比原始函数更灵活指针。

C 没有(并且早期版本的 C++ 没有)这些功能,因此必须使用函数指针。我怀疑它们主要用于与旧代码向后兼容,并且可能用于资源受限的环境中。

【讨论】:

    【解决方案3】:

    compareShapes是函数指针的别名,接受2个const Shape*,返回bool

    compareShapes func = [] (const Shape* s1, const Shape* s2) -> bool {
        return *s1 == *s2; //something boolean
    };
    bool result = func(s1, s2);
    

    或者另一个例子,如果你已经有函数:

    bool someFunc(const Shape* s1, const Shape* s2) { return true; }
    compareShapes funcPtr = someFunc;
    bool result = funcPtr(s1, s2);
    

    更多关于函数指针的信息请见HERE

    【讨论】:

      【解决方案4】:

      为 cmets 添加一些细节:

      这是一个函数指针。 typedef 是为了使它更易于使用。通常 typedef 的格式为“typedef actual_type new_easyer_name”。例如:

      typedef int i
      

      显然,这条线在实践中永远不会出现。但对于更复杂的类型(尤其是那些涉及指针和模板的类型),使用 typedef 可以使您的代码更具可读性。

      此表达式将名称“compareShapes”赋予函数指针类型。在这种情况下,该类型是一个函数,它接受两个 Shape 对象的指针并返回一个布尔值。这样,将函数分配给指针并调用它的代码就更加清晰了。

      这是一个可能在实践中出现的示例。假设 Shape 至少有两个字段:周长和面积。用户可能希望对其中任何一个进行排序:

      #include <vector>
      
      bool perimeterComparison(const Shape* a, const Shape* b){        
          return a->perimeter <= b->perimeter;
      }
      
      bool areaComparison(const Shape* a, const Shape* b){
          return a->area <= b->area;
      }
      
      //Note the capitalization of CompareShapes to show it is a type, not a variable
      typedef bool (*CompareShapes)(const Shape* a, const Shape* b);
      
      void sortShapes(std::vector<Shape*>& shapes, CompareShapes comparison){
          //Lazy programming: bubble sort
          for(int first = 0; first < shapes.length(); shapes++){
              for(int second = first + 1; second < shapes.length(); shapes++){
                  if(!comparison(shapes[first], shapes[second])){
                      Shape* temp = shapes[second];
                      shapes[second] = shapes[first];
                      shapes[first] = shapes[second];
                  }
              }
          }
      }
      
      int main(){
          //This could just as easily point to perimeterComparison or something else valid
          CompareShapes compareFunction = &areaComparison;
      
          std::vector<Shape*> shapes(10);
          for(int i = 0; i < 10; i++){
              shapes[i] = new Shape(); //Initialize the shapes somehow
          }
      
          sortShapes(shapes, compareFunction);
      
          for(int i = 0; i < 10; i++){
              cout << shapes[i] << "\n";
          }
      
          return 0;
      }
      

      【讨论】:

      • “显然这条线永远不会出现在实践中”。微软想和你谈谈。
      • 你的例子不是最好的,因为这个特殊的例子在不使用函数指针的情况下会更容易阅读。恕我直言,一个更好的例子是一个函数,例如两个形状和一个指向比较函数的指针作为参数。
      • @tobi303 你们都完全正确;我只是想演示语法,而不是上下文。我将更新示例。来自 Revolver_Ocelot 评论的 ROFL。
      【解决方案5】:

      您可以使用cdecl 来解释这些类型,但您需要在类名之前插入struct,并替换bool 以将其解析为C 代码:

      cdecl> explain struct bool (*compareShapes)(const struct Shape* , const struct Shape* )
      declare compareShapes as pointer to function (pointer to const struct Shape, pointer to const struct Shape) returning struct bool
      

      然后你需要在心理上撤消这种转变,给予

      compareShapes声明为指向函数的指针(指向const Shape的指针,指向const Shape的指针)返回bool

      【讨论】:

        【解决方案6】:

        compareShapes是一个函数指针,它接受2个类型参数(指向Shape的指针)并返回布尔值。

        您可以分配compareShapes 任何符合此签名的函数。

        例如,

        bool isShapesValid(const Shape* s1, const Shape* s2) 
        

        可以赋值:

        compareShapes objCompareShapes = &isShapesValid;
        

        【讨论】:

          【解决方案7】:
          typedef bool (*compareShapes)(const Shape* s1, const Shape* s2);
          bool CmpShapes(const Shape *s1,const Shape *s2){retunr true;}
          

          compareShapes是比较两个Shape对象的函数原型(签名)

          例如:

          class Shape{};
          class CTest{
               compareShapes m_cmp;
           public:
               CTest(compareShapes _cmpFunc):m_cmp(_cmpFunc){
                   printf("m_cmp: %p %s\n",m_cmp,m_cmp(NULL,NULL)?"true":"false");
               };
           };
          
          void main(){
                 Ctest tst(&CmpShapes);//we pass CmpShapes address.
          }
          

          【讨论】:

            猜你喜欢
            • 2011-12-24
            • 1970-01-01
            • 1970-01-01
            • 2017-01-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多