Longyi Qi - Blog - Use Objective-C Style Block in C++

Use Objective-C Style Block in C++

Oct 05, 2011
Category: programming-languages
Permalink

Just did a refactoring with block in C++ for my thesis project, OCLint, cleaned up quite a lot of duplicated code. I feel excited to share this.

Block, or being called closure or lambda, is a common concept in many languages like Scala, Erlang, Ruby, and so on. And on Apple devices, you can have block in Objective-C, also C/C++.

Block can allow developers to write code at a point invocation that is executed later in the context of the method implementation; and rather than using callbacks to require contextual data needed to perform an operation, with block, developers can directly access local variables by declaring them using __block storage type modifier. 1 (But for the second usage, please consider the side effect of mutable variables within a block.)

If you are familiar with Objective-C, then you can feel it at home, and your craving to have this awesome feature in C++ makes you excited.

As a quick example, here in this piece of code snippet, I need to know which type of cursor they are in clang’s abstract syntax tree, and extract certain types of nodes out from the tree. However, I need different cursor type in different context. So I created a method extractCursor, it will take a block as parameter nodesFilter, and call this block in a if statement to do the real filtering.

const pair<CXCursor, CXCursor> extractCursor(StringSourceCode code, 
        bool(^nodesFilter)(CXCursor, CXCursor), 
        int filteredIndex) {
  CXIndex index = clang_createIndex(0, 0);
  CXTranslationUnit translationUnit =
          StringSourceCodeToTranslationUnitUtil::
            compileStringSourceCodeToTranslationUnit(code, index);
  vector<pair<CXCursor, CXCursor> > *nodes = 
          new vector<pair<CXCursor, CXCursor> >();
  clang_visitChildren(
    clang_getTranslationUnitCursor(translationUnit),
    extractCursorVisitor, 
    nodes);
  vector<pair<CXCursor, CXCursor> > *filteredNodes = 
          new vector<pair<CXCursor, CXCursor> >();
  for (int index = 0; index < nodes->size(); index++) {
    pair<CXCursor, CXCursor> nodesPair = nodes->at(index);
    if (nodesFilter(nodesPair.first, nodesPair.second)) {
      filteredNodes->push_back(nodesPair);
    }
  }
  if (filteredIndex < 0) {
    filteredIndex += filteredNodes->size();
  }
  return filteredNodes->at(filteredIndex);
}

And the real filter is here, based on the context, I need to extract a cursor as an Objecitve-C method declaration, so I can easily access current node extractCursor give to me, so check the type of it, and return the result boolean value back to the extractCursor for the rest of the logic.

void NPathComplexityRuleTest::checkRule(string source, bool isViolated) {
  StringSourceCode strCode(source, "m");
  pair<CXCursor, CXCursor> cursorPair = extractCursor(strCode, 
    ^bool(CXCursor node, CXCursor parentNode) {
      Decl *decl = CursorUtil::getDecl(node);
      return decl && isa<ObjCMethodDecl>(decl);
  });
  checkRule(cursorPair, isViolated);
}

If your C++ program only intend to work on Apple devices, and want to try this awesome block feature in your code, I highly recommend you read this article 2 from Joachim Bengtsson, you can get a detail understanding from there.

References

1 http://developer.apple.com/library/ios/documentation/cocoa/Conceptual/Blocks/Blocks.pdf

2 Programming with C Blocks

Please leave comments and further discussions to lqi+blog@longyiqi.com or @longyiqi.

This article is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License .