2016-09-12 4 views
8

코드에 단일 헤더 요구 사항이 있습니다. 즉, 선언과 정의가 별도의 헤더와 소스 파일로 분리되지 않아야합니다. 나는 올바르게 구현했고,이 헤더 파일은 단일 소스 파일에만 포함되도록 의도 된 나의 사용 사례를 위해 의도 된대로 작동합니다.단일 헤더에 대한 변수의 재정의를 피합니다.

여러 개의 소스 파일 (두 개 이상의 .cpp에 포함되어 있음)에서 사용할 때 일부 변수가 다시 선언되는 줄에 따라 링커 오류로 인해 실패합니다. 그건 내가 같은 코드했습니다 때문입니다 -

#ifndef HEADER_HPP 
#define HEADER_HPP 

.... 

std::streambuf const *R_coutbuf = std::cout.rdbuf(); 
std::streambuf const *R_cerrbuf = std::cerr.rdbuf(); 
std::streambuf const *R_clogbuf = std::clog.rdbuf(); 

void doSomething(){ 
    [uses if(R_coutbuf) and others] 
} 

.... 

#endif HEADER_HPP 

지금 가장 좋은 방법은 헤더 파일에서 그 바르를 선언하고 정의/하나의 cpp 파일에 할당하는 것입니다,하지만 난 할 수 있도록하려는 말했듯 이 작업은 단일 헤더 파일로 수행하십시오. 어떤 소스 파일에 여러 개의 파일이 포함되면 재 선언이 생기는 문제가 발생합니다.

지금까지 내가이 일을 할 수 있어야하는 방법을 잘 모르겠어요하지만이 개 아이디어했습니다 - 나는 그것에 대해 확실하지 않다

#ifdef DEFINE_VARIABLES 
#define EXTERN /* nothing */ 
#else 
#define EXTERN extern int 
#endif /* DEFINE_VARIABLES */ 

EXTERN global_variable = something; 

을,이 경우에도 작동합니다?

#ifndef HEADER_HPP 
#define HEADER_HPP 

.... 

namespace R { 

    namespace { 
     std::streambuf const *R_coutbuf = std::cout.rdbuf(); 
     std::streambuf const *R_cerrbuf = std::cerr.rdbuf(); 
     std::streambuf const *R_clogbuf = std::clog.rdbuf(); 
    } 
    void doSomething(){ 
     [uses if(R_coutbuf) and others] 
    } 
} 

.... 

#endif HEADER_HPP 

내가이를 수있는 다른 방법이 있나요 -

그리고 내가 생각 두 번째 방법은 익명의 공간에 넣어하는 것입니다,이 성공적으로 지금까지의 건물을 시도하고있다? 위에서 설명한 방법 중 하나에 문제가 있습니까?

+1

당신이 뭔가 "작동"인지 확실하지 않은 경우, 또는하지, 더 빨리 단지에 일을하려고 할 것입니다 보인다 intertubes에있는 누군가가 당신을 위해 그것을 알아낼 때까지 기다리는 대신에,보십시오. –

+1

_header.hpp_를 포함하여 __before__ 하나의 _.cpp_ 파일에서 __exactly__ 하나의 매크로를 정의하는 한'DEFINE_VARIABLES'/참고 :'int' 이외의 변수가 필요할 수도 있으므로 정의를'#define EXTERN extern'으로 변경하십시오. – CristiFati

+0

흥미로운 질문이지만 ... 원한다면 cpp 파일에 헤더 파일을 포함시켜야합니다 ... 왜 헤더 파일을 없애고 그 내용을 cpp 파일의 초기 부분에 쓰지 않습니까? – max66

답변

5

당신은 당신의 변수 함수에서 로컬 정적 변수를 만들 수 있습니다 :

inline std::streambuf const*& R_coutbuf() { 
    static std::streambuf const* b = std::cout.rdbuf(); 
    return b; 
} 
+0

이것은 처음 호출 될 때 인스턴스화되고 매번 같은 값을 반환합니다. 이러한 변수를 초기화하기 전에'init()'함수 호출을 제공해야합니다. 맞습니까? 단 1 cpp에서 한 번 호출해야하거나 내 머리글에서 한 번 호출 할 수 있습니까? –

+0

최초로 호출 될 때 인스턴스화됩니다 (예). 왜'init()'함수가 필요한지 모르겠다. 초기화가 이미있다. 매번 같은 값을 반환하지는 않습니다. 원하는 경우 포인터를 다시 장착 할 수 있도록 의도적으로 포인터에 대한 참조를 반환했습니다. –

+0

내가 조금 잘못 이해했는데, 그것이 게으른 초기화라는 것을 알고 기뻤습니다. –

1

위에서 설명한 방법 중 하나에 문제가 있습니까?

매크로 트릭

  • 프로
    • 는 오브젝트 파일의 변수의 최소 수를 생성합니다. 익명 네임 스페이스의 단점을 참조하십시오.
  • 단점
    • 매우 깨지기 쉬운 . 헤더를 포함 할 때 프로그래머는 다른 기존 소스 중 에 변수 정의가 포함되어 있는지 여부를 알아야합니다. 소스 파일의 수는 매크로 트릭의 단점이없는

내부 연결 (익명 네임 스페이스)

  • 프로
    • 이 증가 할 때 확장 성이 좋지 않습니다.
  • 단점
    • 변수의 자신의 사본이있을 것이다 헤더를 포함하는 각각의 오브젝트 파일.확실하지는 않지만 변수는 const이고 런타임에 모두 동일한 값을 갖습니다. 링커 중복을 제거 할 수 있습니다. 어쨌든, 그 차이는 단지 당신의 프로그램에 대해 단지 몇 바이트 가치입니다. 공유 변수를 수정하는 대신 개별 변수를 수정하면 프로그램의 의미가 변경됩니다.

비교를 위해, 우리가 당신을 배제 한 별도의 소스 파일 옵션을 생각해 보자.

  • 프로
    • 매크로 트릭과 같은 오브젝트 파일에서 변수의 최소 수를 생성합니다.
    • 매크로 트릭의 단점이 없습니다.
  • 단점
    • 없음 (별도의 소스가 단독으로 사기를 제출할 것을 고려하지 않은 경우).

내가이를 수있는 다른 방법이 있나요 ?

아니요. 익명 네임 스페이스 대신 static 키워드를 사용하여 내부 연결을 선언 할 수 있습니다.


추신. 헤더에 템플릿이 아닌 함수를 정의하는 경우 템플릿 함수는 인라인으로 선언해야합니다. 익명 네임 스페이스 예제가이 작업을 수행하지 못합니다.