2017-02-06 9 views
4

CTP 14와 CRTP (호기심 반복 템플릿 패턴) 및 Boost.Hana (또는 원하는 경우 boost::mpl)의 조합을 사용하여 명시 적 선언없이 컴파일 타임 (또는 정적 초기화 시간)에 유형 목록을 작성 하시겠습니까? 예를 들어 C++ 14 메타 프로그래밍 : 컴파일/초기화시 형식 목록 자동 작성

, 나는이 ( Coliru에 참조) 같은 것을 가지고

#include <iostream> 
#include <boost/hana/tuple.hpp> 
#include <boost/hana/for_each.hpp> 

namespace 
{ 
    struct D1 { static constexpr auto val = 10; }; 
    struct D2 { static constexpr auto val = 20; }; 
    struct D3 { static constexpr auto val = 30; }; 
} 

int main() 
{ 
    // How to avoid explicitly defining this? 
    const auto list = boost::hana::tuple< D1, D2, D3 >{}; 

    // Do something with list 
    boost::hana::for_each(list, [](auto t) { std::cout << t.val << '\n'; }); 
} 

나는 종류의 명시 적 목록을 피하려고 - D1, D2, 그리고 D3 -에서 list의 생성은 컴파일러에게 또는 클래스 선언 주위에 "이 클래스를 실행 목록에 추가"할 수 있어야하는 것처럼 수동으로 해당 목록을 유지해야한다는 것을 의미하기 때문입니다. (궁극적 인 목적은 공장 등록을 자동화하는 것입니다. 이것은 누락 된 메커니즘입니다.)

일부 상속 및/또는 메타 프로그래밍을 사용하여 컴파일 타임이나 정적 초기화 시간에 목록을 구성 할 수 있습니까?

+0

http://b.atch.se/ 마음에 온다 -하지만위원회에 노력하고있다 그런 트릭을 허락하는 허점을 패치하십시오, 그래서 아마 그것을 사용해서는 안됩니다. – Quentin

답변

1

컴파일시에는 "상태 저장"메타 프로그래밍이 필요합니다. 이 문서 here에서, 필립 Roséen은 매우 고급 C++ (14) 사용하여 다음과 같은 구현하는 방법에 대해 설명 : C++ 11에서 의미 기반 개념을 구현하기 위해

LX::push<void, void, void, void>(); 
LX::set<0, class Hello>(); 
LX::set<2, class World>(); 
LX::pop(); 

LX::value<> x; // type_list<class Hello, void, class World> 

또한, 매트 카라가 사용 유사한 기술을의 video 참조 슬라이드 # 28에서 slides

물론 이러한 기술은 준수 2 단계 이름 조회를 지원하는 컴파일러에 의존합니다.

또는 대신 런타임 등록을 지원하도록 코드를 재구성 할 수 있습니다. 이는 훨씬 간단하며 MSVC와 같은 컴파일러에서 이식 할 수 있습니다. 이것은 Prove 또는 args과 같은 라이브러리를 사용하는 것입니다.

template<class T, class F> 
int auto_register_factory() 
{ 
    F::template apply<T>(); 
    return 0; 
} 

template<class T, class F> 
struct auto_register 
{ 
    static int static_register_; 
    // This typedef ensures that the static member will be instantiated if 
    // the class itself is instantiated 
    typedef std::integral_constant<decltype(&static_register_), &static_register_> static_register_type_; 
}; 

template<class T, class F> 
int auto_register<T, F>::static_register_ = auto_register_factory<T, F>(); 

그런 다음 자신의 CRTP 클래스를 작성할 수 있습니다 : 그것은 일반적인 auto_register 클래스 사용

struct foo_register 
{ 
    template<class T> 
    static void apply() 
    { 
     // Do code when it encounters `T` 
    } 
}; 

template<class Derived> 
struct fooable : auto_register<Derived, foo_register> 
{}; 
+0

CRTP 비트는 제가 찾고 있던 마법입니다. 감사! – metal

+0

다음은 [이 기법의 실제 동작] (http://coliru.stacked-crooked.com/a/de4467d26dd02b42)의 전체 데모입니다. 'static_register_'가 최적화되기 때문에 서면으로 자동 등록을 할 수 없었기 때문에 약간 수정되었습니다. 그것은 Clang과 GCC에서 작동합니다. – metal

+0

@metal 문제는 템플릿 클래스가 인스턴스화되지 않을 수 있다는 것입니다. 따라서 기본 생성자를 추가하거나 기본 클래스의 함수를 참조하는 것 (즉, this-> register_')은 강제로 또 다른 방법입니다. –

4

네임 스페이스 또는 다른 범위에서 모든 유형의 컴파일 타임 튜플을 얻고 싶습니다. 그렇게하기 위해서는 C + +에 아직 추가되지 않은 정적 리플렉션이 필요합니다 (그러나 당신이 발견 한 것처럼 매우 유용 할 것입니다). one proposal for static reflection hereN4428 proposal here을 읽을 수 있습니다.

임시 해결 방법으로 매크로를 작성하여 유형을 정의하고 정적 초기화 중에 레지스트리에 암시 적으로 추가 할 수 있습니다.

+0

컴파일러는 자동으로 목록을 자동으로 검색 할 필요가 없습니다. 나는 방아쇠 (예를 들어, 정책 클래스 또는 일부 CRTP에서 상속)로 각각 플래그를 지정하여 도움을 줄 수 있습니다. 내가 피하려고하는 것은 자동 등록 된 클래스 목록을 손으로 유지하는 것입니다. – metal

+0

[Boost.Preprocessor와 함께 할 수있는] (http://stackoverflow.com/a/19630812/201787). 아아, 나는 조금 더 우아한 뭔가를 원했다. – metal

+0

그래, 클래스를 정적 ​​목록에 추가하는 CRTP 클래스에서 상속받을 수 있지만 초기화 순서 문제와 인스턴스화 깊이 문제는 매우 빠르게 발생합니다. – thirtythreeforty

1

내가 지금 당장이 작업을 수행하는 것을 알고있는 유일한 방법은 here으로 설명한 상태 저장 메타 프로그래밍입니다. 그러나 이것은 구현하기가 까다 롭고 어렵고,위원회는이를 무효로 판정하려고 시도하고 있습니다.

+0

[CRTP로 무엇을하려했는지에 대한 분석은 여기에 있습니다.] (https://sourceforge.net/p/loki-lib/discussion/93010/thread/bf08774d/), 최신 컴파일러에서는 작동하지 않습니다. . 나는 더 이상 마법적이고 C++ arcana가 그 격차를 좁힐 수 있기를 바랬다. – metal

+1

CRTP를 사용하면 컴파일 타임이 아닌 정적 초기화 시간에 유형을 등록 할 수 있습니다. 그것은 당신에게 충분하지 않을 수도 있습니다. –

+0

좋은 콜 : 정적 초기화와 컴파일 타임을 구별하지 못했지만 필자는 있어야합니다. 필자의 경우에는 정적 초기화 시간이 충분해야하지만, 여전히 정확한 메커니즘으로는 나를 벗어날 수 있습니다. 나는 내 질문에 표현을 분명히했다. – metal