컴파일 타임에 메소드가 정확히 한 곳에서 호출되는지 확인하십시오. 궁금합니다. 함수가 두 번

컴파일 타임에 메소드가 정확히 한 곳에서 호출되는지 확인할 수 있는지 궁금합니다.

함수가 두 번 이상 (예 : 루프에서) 호출되면 괜찮지 만 두 개의 개별 루프에서 호출해서는 안됩니다.

이것은 두 부분으로 나눌 수 있습니다, 나는 또한 중 일부를 커버 솔루션에 관심이 있어요 :
(A) 방법을 확인이 적어도 하나 개의 장소에 호출
에 호출 (b)의 방법을 위해 가장 한 곳에서

코드 구조를 완전히 제어 할 수 있으며 동일한 아이디어를 얻는 다른 관용구도 환영합니다.

// class.h

class MyClass {
  public:
    void my_method();
}

다음은 컴파일해서는 안됩니다 (전화하지 마십시오)

#include "class.h"

int main() {
  MyClass my_class;
}

다음은 컴파일하지 않아야합니다 (여러 곳에서 호출)

#include "class.h"

int main() {
  MyClass my_class;
  my_class.my_method();
  while(true) {
    my_class.my_method();
  }
}

다음은 컴파일해야합니다 (정확히 한 곳에서 호출).

#include "class.h"

int main() {
  MyClass my_class;
  while(true) {
    my_class.my_method();
  }
}


답변

낮은 기술 접근 ​​방식 :

코드 구조 (빌드 시스템 포함)를 제어 할 수 있기 때문에 여기 저 기술 솔루션이 있습니다.

  • 함수 이름을 충분히 고유하게 만드십시오
  • 코드에서 함수 이름을 grep하십시오. 선언과 정의가 같은 위치에 있다고 가정하면 두 번 예상됩니다.
    • 헤더에 한 번
    • 단일 통화 사이트에서 한 번

또는

정말로 정말로 C ++로 해결하고 싶다면 시도해보십시오.

  • 컴파일 타임 카운터를 사용하여 컴파일 단위 내의 사용 횟수를 파악하십시오.
  • 헤더가 여러 컴파일 단위에 포함 된 경우 함수가 ODR을 위반하는지 확인하십시오.

그러나 컴파일 타임 카운터는 검은 마술입니다 (예 : I 및 TMP를 정말로 좋아합니다).이 목적으로 ODR 위반을 강제하는 것은 비슷한 부두처럼 보입니다 (적어도 연결에 실패한 테스트 사례가 필요합니다).

그러나 진지하게 :

이러지 마 무엇을하든 래퍼 함수를 ​​사용하면 거의 노력하지 않고 왜곡 할 수 있습니다.

auto call_my_method(MyClass& o)
{
   return o.my_method();
}

MyClass::my_method()랩퍼에서만 호출됩니다. 다른 사람들은 컴파일러에 의해 인라인 된 래퍼를 호출합니다.

다른 사람들이 제안한 바와 같이 : 당신이하려는 일을 설명한다면 훨씬 도움이 될 수 있습니다.


답변

다음은 작동 할 수있는 대략적인 아이디어입니다 (댓글이 너무 길지만 좋은 SO 답변에는 불완전합니다).

템플릿 인스턴스화 수를 계산 / 확인하여이를 달성 할 수 있습니다.
템플릿은 사용시 에만 인스턴스화됩니다 .

마찬가지로 템플릿 메소드 / 함수 본문은 호출되지 않은 경우 구문 분석 또는 컴파일 또는 링크되지 않습니다 (유효한 구문 보장 이외). 이것은 그들의 몸 안에서 어떤 인스턴스도 만들어지지 않았다는 것을 의미합니다).

전역 인스턴스화 횟수와 정적 어설 션을 유지하는 템플릿 (또는 과거 인스턴스화를 확인하는 다른 TMP 메커니즘)을 유지 관리하는 템플릿을 만들 수 있습니다.


답변

C 전처리 기와 GNU 인라인 어셈블리를 사용하여이 질문에 대한 부분적인 해결책이 있습니다.

헤더 파일 a.h:

struct A {
    // Do not call this method directly, use the macro below to call it
    int _method_vUcaJB5NKSD3upQ(int i, int j);
};

// Use inline assembly to ensure that this macro is used at most once
#define method_vUcaJB5NKSD3upQ(args...) \
    _method_vUcaJB5NKSD3upQ(args); \
    asm (".global once_vUcaJB5NKSD3upQ; once_vUcaJB5NKSD3upQ:");

구현 파일 a.cc:

#include <iostream>
#include "a.h"

int A::_method_vUcaJB5NKSD3upQ(int i, int j) { return i+j+5; }

// Ensure that the macro is used at least once
extern "C" const char once_vUcaJB5NKSD3upQ;
static const char get_vUcaJB5NKSD3upQ = once_vUcaJB5NKSD3upQ;

int main() {
    A a;
    for(int i=0; i<7; i++) {
        // Use a separate statement to call the method
        // (terminated by a semicolon, it cannot be a sub-expression)
        auto x = a.method_vUcaJB5NKSD3upQ(2, 3);
        std::cout << x << std::endl;
    }
    return 0;
}

이 솔루션은 프로그램이 래퍼 매크로를 사용하지 않고 밑줄로 시작하는 메소드를 직접 호출하는 것을 막지 않는다는 점에서 부분적입니다.


답변

constexpr 카운터를 사용하십시오. 다른 질문에 구현이 있습니다.