2013-11-20 2 views
14

과부하 해결 세트를 검사하려면 어떻게해야합니까?주어진 호출 사이트에 대해 설정된 과부하 해결 방법을 검사하는 방법

여러 통화 사이트에서 4 개의 경쟁 함수가 사용되었습니다. 하나의 호출 사이트에서, 나는 하나의 함수가 호출되기를 기대하지만, 다른 함수는 컴파일러에 의해 선택된다. 나는 이유를 알지 못한다/그것은 사소하지 않다. 무슨 일이 일어나고 있는지 알기 위해, 나는 기능을 켜고 끄기 위해 enable_if/disable_if을 사용하고있다. 그러나 이것은 정말로 느리고/지루한/성가신 일이다.

그래서 컴파일러에서 "왜?"라고 말하고 싶습니다. 과부하 해상도 설정에서

  • 모든 기능, 과부하 해상도에서 거부
  • 모든 기능을 설정, ADL에 의해 발견

    • 모든 기능과 왜 그들이 거부되었고, : 즉,이 단일 통화 사이트입니다
    • 과부하 해결 세트에있는 기능의 순위와 해당 순위의 이유.

    액세스 제어에 대한 정보는 필요하지 않습니다.

    기본적으로 전화 사이트를 #pragma 또는 이와 유사한 것으로 표시하려고합니다 (__builtin ...). 그러나 libclang도 옵션이 될 것입니다.

    나는 tip-of-trunk clang 및 gcc에 액세스 할 수 있지만 필요하면 다른 컴파일러/도구를 설치할 수 있습니다.

  • +2

    다소 과장되어 있지만 과부하 된 묶음에서 어떤 특정 기능이 호출 될지를 꾸준히 예측할 수없는 경우 가난한 디자인입니다. 오버로드 버전은 분명히 차별화되어야합니다. – Mikhail

    +1

    @Mikhail 올바른 오버로드를 예측하고있었습니다. 그것은 const 객체에서 비 const 멤버 함수를 호출했기 때문에 선택되지 않았습니다 (const overload ...를 추가하는 것을 잊어 버렸습니다 ...). 나도 알아, 유니버설 참조 + 오버로드를 섞어하지 마십시오 ... 옳은 일을하지 않는 한.컴파일러는 쉽게 처리 할 수 ​​있습니다. – gnzlbg

    답변

    5

    clang 플러그인을 호출하여 어떤 함수가 호출되는지 그리고 다른 함수가 오버로드 집합에 있는지를 상상할 수 있습니다. 조회 규칙을 추적하고 왜 과부하 집합의 후보가 삭제되고 왜 선택된 함수가 과부하 집합에서 가장 적합한 후보인지는 알 수있을 것입니다.

    오버로드 세트 등을 결정하는 데 익숙하지 않았습니다. 그러나 다음과 같은 간단한 시작점이 있습니다. 특정 이름 (현재 하드 코드 된) 인 경우 호출되는 clang 플러그 인)가 발견되었습니다. 또한 발견 된 오버로드를 인쇄합니다.

    나는 코드를 컴파일하고 (물론,이는 make 파일에 저장됩니다) 명령으로 실행 해요 : 그렇지 않으면 '아무튼 : 디버그 정보와 함께 내장되어 사용되는 그 소리의 버전

    /opt/llvm-debug/bin/clang -I/usr/include/c++/4.2.1 -I/opt/llvm-debug/include -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -g -fno-exceptions -fno-rtti -c -o MacOS/overloads.o overloads.cpp 
    /opt/llvm-debug/bin/clang -L/opt/llvm-debug/lib -Wl,-undefined,dynamic_lookup -dynamiclib -o MacOS/overloads.dylib MacOS/overloads.o 
    /opt/llvm-debug/bin/clang -cc1 -load MacOS/overloads.dylib -plugin overloads -plugin-arg-overloads argument -fexceptions tst.cpp 
    

    디버그 기호를 찾은 것 같습니다. 아마도 도구를 직접 빌드하고 clang 내에서 실행하지 않는 방법을 찾아야합니다.

    #include <clang/Frontend/FrontendPluginRegistry.h> 
    #include <clang/Frontend/CompilerInstance.h> 
    #include <clang/Lex/Preprocessor.h> 
    #include <clang/Lex/PPCallbacks.h> 
    #include <clang/AST/ASTConsumer.h> 
    #include <clang/AST/AST.h> 
    #include <clang/AST/RecursiveASTVisitor.h> 
    #include <clang/Sema/Sema.h> 
    #include <clang/Sema/Lookup.h> 
    #include <llvm/Support/raw_ostream.h> 
    #include <string> 
    
    using namespace clang; 
    using namespace llvm; 
    typedef clang::CompilerInstance CI; 
    typedef clang::DeclGroupRef  DGR; 
    typedef clang::DiagnosticsEngine DE; 
    
    // ---------------------------------------------------------------------------- 
    
    namespace 
    { 
        struct Consumer: clang::ASTConsumer 
        { 
         Consumer(CI& c, std::string const& name): c_(&c), name_(name) {} 
         bool HandleTopLevelDecl(clang::DeclGroupRef DG); 
         CI*   c_; 
         std::string name_; 
        }; 
    } 
    
    // ---------------------------------------------------------------------------- 
    
    struct Visitor: RecursiveASTVisitor<Visitor> 
    { 
        CI*   c_; 
        std::string name_; 
        Visitor(CI* c, std::string const& name): c_(c), name_(name) {} 
    
        bool VisitCallExpr(CallExpr* d); 
    }; 
    
    bool Visitor::VisitCallExpr(CallExpr* c) { 
        FunctionDecl* fun = c->getDirectCallee(); 
        if (fun && fun->getNameAsString() == this->name_) { 
         SourceLocation w(c->getExprLoc()); 
         DE &de(this->c_->getDiagnostics()); 
         int id = de.getCustomDiagID(DE::Warning, "function call: %0"); 
         int info = de.getCustomDiagID(DE::Note, "function called"); 
         DiagnosticBuilder(de.Report(w, id)) 
          << fun->getNameAsString() 
          ; 
         DiagnosticBuilder(de.Report(fun->getLocStart(), info)) 
          << fun->getNameAsString() 
          ; 
         Sema& sema = this->c_->getSema(); 
         LookupResult result(sema, fun->getDeclName(), w, Sema::LookupOrdinaryName); 
         DeclContext* context = fun->getDeclContext(); 
         if (sema.LookupName(result, sema.getScopeForContext(context))) { 
          int over = de.getCustomDiagID(DE::Note, "function overload"); 
          LookupResult::Filter filter = result.makeFilter(); 
          while (filter.hasNext()) { 
           DiagnosticBuilder(de.Report(filter.next()->getLocStart(), over)) 
            ; 
          } 
          filter.done(); 
         } 
        } 
        //else { 
        // // I think the callee was a function object or a function pointer 
        //} 
    
        return true; 
    } 
    
    void doDecl(Consumer* c, Decl* d) { 
        Visitor(c->c_, c->name_).TraverseDecl(d); 
    } 
    
    // ---------------------------------------------------------------------------- 
    
    bool Consumer::HandleTopLevelDecl(DeclGroupRef DG) { 
        std::for_each(DG.begin(), DG.end(), 
         std::bind1st(std::ptr_fun(&doDecl), this)); 
        return true; 
    } 
    
    // ---------------------------------------------------------------------------- 
    
    namespace 
    { 
        class Plug 
         : public clang::PluginASTAction 
        { 
        protected: 
         ASTConsumer* 
         CreateASTConsumer(CompilerInstance& c, llvm::StringRef); 
         bool ParseArgs(clang::CompilerInstance const&, 
             std::vector<std::string> const&) { 
          return true; 
         } 
        }; 
    } 
    
    ASTConsumer* 
    Plug::CreateASTConsumer(CompilerInstance& c, llvm::StringRef) { 
        return new Consumer(c, "foo"); 
    } 
    
    static clang::FrontendPluginRegistry::Add<Plug> 
        registerPlugin("overloads", "report overloads of a function at a call"); 
    

    코드가 예쁘지 않고 찾고있는 것을 실제로 수행하지 않습니다. 그러나 함수 선언을 좀 더 멋지게 형식화하여 아마도 Sema 객체를 사용하여 비트를 조사하는 것이 왜 일치하지 않는지 등 당신이 찾고있는 도구에 합리적으로 가까운 코드를 얻을 수 있다고 생각합니다.