2010-04-16 3 views
0

간단한 컴파일 타임 메타 프로그래밍과 함께 할 수있는 코드를 작성 중입니다. 빈 struct 태그를 컴파일 타임 기호로 사용하는 것이 일반적입니다. 일부 런타임 구성 요소를 사용하여 태그를 꾸밀 필요가 있습니다. 정적 변수는 (메타 프로그래밍을 가능하게하기 위해) 유일한 방법이지만, 정적 변수는 전역 선언을 필요로합니다. 정적 변수의 초기화를 클래스 변수가 아닌 함수 안에 선언하여 시퀀싱하는 것에 대한 Scott Myers의 제안 (Effective C++ 제 3 판)을 참고하십시오.컴파일 시간 문자열 리터럴을 사용한 메타 프로그래밍

그래서 다음 코드를 생각해 냈습니다. 가설은 런타임시 문자열 리터럴을 사용할 수있는 컴파일 타임 기호를 갖게한다는 것입니다. 내가 희망하는 것을 놓치지 않고, 올바르게 작동 할 것입니다. 런타임 템플릿을 사용하기 전에 런타임 필드를 채우기 만하면됩니다. .

#include <string> 

template<class Instance> 

class TheBestThing { 
public: 
    static void set_name(const char * name_in) { 
     get_name() = std::string(name_in); 
    } 
    static void set_fs_location(const char * fs_location_in) { 
     get_fs_location() = std::string(fs_location_in); 
    } 
    static std::string & get_fs_location() { 
     static std::string fs_location; 
     return fs_location; 
    } 
    static std::string & get_name() { 
     static std::string name; 
     return name; 
    } 
}; 
struct tag {}; 
typedef TheBestThing<tag> tbt; 

int main() 
{ 
    tbt::set_name("xyz"); 
    tbt::set_fs_location("/etc/lala"); 

    ImportantObject<tbt> SinceSlicedBread; 
} 

편집 : 제작 커뮤니티 위키.

+1

@ 하산 : 나는 지금 당장 그것을 알아 챘다. 하지만 여전히 더 나은 태그를 사용할 수 있습니다. :) -1. –

+0

태그는이 특정 질문을 찾는 모든 사용자에게 적합합니다. –

+1

그러나 질문은 무엇입니까? –

답변

1

마침내 문제가 무엇인지 이해했으며 솔루션이 많은 경우 해결하지 못했습니다.

로컬 정적 변수 사용의 목표는 "Initialization Order Fiasco"("Destruction Order Fiasco"를 해결하지 못함)에서 안전하게 사용할 수 있도록 처음 사용할 때 초기화를 제공하는 것입니다.

그러나 디자인을 사용하면 crash을 효과적으로 방지하면 값을 사용하기 전에 변수를 사용하는 문제를 방지 할 수 있습니다.

ImportantObject<tbt> SinceSliceBread; // using an empty string 

tbt::set_name("xyz"); 

는 다음의 사용과 비교 다음은 name

std::string& tbt::get_name() { static std::string MName = "xyz"; return MName; } 

은 생성뿐만 아니라 는 처음 사용할 때을 초기화되지 않았습니다. 초기화되지 않은 이름을 사용하는 이유는 무엇입니까?

이제 솔루션이 작동하지 않는다는 것을 알게 되었으니 조금만 생각해보십시오. 사실 우리는이를 자동화하고 싶습니다 :

struct tag 
{ 
    static const std::string& get_name(); 
    static const std::string& get_fs_location(); 
}; 

(아마도 몇 가지 접근이를 수정하기로)

내 첫 번째 (쉽게) 솔루션 (bouh 형태 보증되지 않음) 매크로를 사용하는 것입니다 :

#define DEFINE_NEW_TAG(Tag_, Name_, FsLocation_)    \ 
    struct Tag_             \ 
    {               \ 
    static const std::string& get_name() {     \ 
     static const std::string name = #Name_;     \ 
     return name;           \ 
    }               \ 
    static const std::string& get_fs_location() {    \ 
     static const std::string fs_location = #FsLocation_; \ 
     return fs_location;          \ 
    }               \ 
    }; 

다른 해결책으로는 boost::optional을 사용하여 값이 아직 초기화되지 않았 음을 감지하고 그에 따라 달라지는 값의 초기화를 연기 할 수 있습니다.

+0

예, 초기화 순서 문제를 언급하지 않았습니다. 제 관심사는 컴파일 타임에 사용할 수있는 문자열을 사용하여 컴파일 타임 태그와 연결할 수있는 쉬운 방법이었습니다. Boost :: MPI 문자열 리터럴은 약간의 해킹이며 C++ 0x는 문제를 해결합니다. 그래서 Myers의 책에서 static-string-declared-in-function 기술을 선택했습니다. 분석을 해주셔서 감사 드리며, 매크로는 확실히 코드를 스토리처럼 읽을 수있게 해줍니다. –

+0

질문에 가치를 더하는 대답으로 받아들입니다. 그러나 많은 사람들이이 질문에 대해 토론했으며 질문에서 코드를 연속적으로 편집했습니다. Boost 옵션은 초기화 문제를 방지하는 아주 좋은 방법입니다. 코드를 내 프로젝트에서 내부 용으로 사용하기 때문에 즉시 추가하지 않을 수도 있습니다. –

관련 문제