2012-06-28 2 views
1

경고 : 문제를 설명하는 데 필요한 사전 지식이 필요합니다. 첫째 Vandevoorde 및 Josuttis에의 채널 16.1에서 설명하는 명명 된 템플릿 인수 관용구 편리하게 Boost.Parameter 라이브러리 위의 코드는 이름으로 arbritrary 위해 BreadSlicer의 선택 템플릿 매개 변수를 대체 할 수Boost.Parameter : CRTP와 조합 된 명명 된 템플릿 인수

#include <iostream> 
    #include <typeinfo> 
    #include <boost/parameter.hpp> 
    #include <boost/static_assert.hpp> 

    struct DefaultPolicy1 {}; 
    struct DefaultPolicy2 {}; 

    typedef boost::parameter::void_ DefaultSetter; 

    BOOST_PARAMETER_TEMPLATE_KEYWORD(Policy1_is) 
    BOOST_PARAMETER_TEMPLATE_KEYWORD(Policy2_is) 

    typedef boost::parameter::parameters< 
      boost::parameter::optional<tag::Policy1_is>, 
      boost::parameter::optional<tag::Policy2_is> 
    > PolicySelector; 

    template 
    < 
      class PolicySetter1 = DefaultSetter, 
      class PolicySetter2 = DefaultSetter 
    > 
    class BreadSlicer 
    { 
      typedef typename PolicySelector::bind< 
        PolicySetter1, 
        PolicySetter2 
      >::type Policies; 

    public: 
      // extract policies: 
      typedef typename boost::parameter::value_type< 
        Policies, tag::Policy1_is, DefaultPolicy1 
      >::type P1; 

      typedef typename boost::parameter::value_type< 
        Policies, tag::Policy2_is, DefaultPolicy2 
      >::type P2; 
    }; 

작성 할 수 있습니다 그들 Policy1_isPolicy2_is. 따라서 많은 기본 매개 변수가있는 정책 기반 설계가 매우 편리합니다. 정책 기반의 디자인과 매우 미묘한 ODR 위반 (에 대한 설명 Alexandrescu에 의해이 오래된 post 참조) 피하기 위해

int main() 
{ 
     typedef BreadSlicer<> B1; 

     // can override any default policy 
     typedef BreadSlicer< Policy1_is<int> > B2; 
     typedef BreadSlicer< Policy2_is<char> > B3; 

     // order of policy-setting is irrelevant 
     typedef BreadSlicer< Policy1_is<int>, Policy2_is<char> > B4; 
     typedef BreadSlicer< Policy2_is<char>, Policy1_is<int> > B5; 

     // similar static asserts work for B1 ... B4  
     BOOST_STATIC_ASSERT((std::is_same<B5::P1, int >::value)); 
     BOOST_STATIC_ASSERT((std::is_same<B5::P2, char>::value)); 

     return 0; 
} 

, 나는 명명 된 템플릿 인수에 CRTP 패턴을 적용 할 수 있도록하고 싶습니다 :

int main() 
    { 
      // ERROR: this code does NOT compile! 
      struct CuriousBreadSlicer 
      : 
        BreadSlicer< Policy1_is<CuriousBreadSlicer> > 
      {}; 

      typedef CuriousBreadSlicer B6; 

      BOOST_STATIC_ASSERT((std::is_same<B6::P1, CuriousBreadSlicer>::value)); 
      BOOST_STATIC_ASSERT((std::is_same<B6::P2, DefaultPolicy2 >::value)); 

      return 0; 
    } 

그러나, Boost.Parameter 구현은 위의 일부 내부 static_assert는 (VC10 SP1)과 같은 메시지

의 주요 실패 때문에 컴파일에 실패 :: CuriousBre을 adSlicer이 정적 검사가 해제 할 수 있습니다 :

이 질문 '__is_base_of'정의되지 않은 클래스는 고유 유형의 특성을 컴파일러하는 인수로 사용할 수 없습니다 '? 매크로 또는 템플릿 트릭을 통해? 가능한 워크 어라운드에 관해서

:

  1. 위 코드 this handwritten code 기능적으로 동일하다. 이 코드에서는 CRTP 패턴이 작동합니다. 그러나 은 Boost.Parameter 라이브러리가 매우 편리하므로 많은 보일러 플레이트 코드가 필요합니다. 은 자동화합니다.
  2. 템플릿의 목록에서 항상 CRTP 매개 변수를 먼저 요구하고 Policy1_is 클래스로 래핑하지 않아도됩니다. 이렇게하면 컴파일 시간 오류가 해결되지만 재정의의 순서 독립성이 손실됩니다.

그래서 저는 골프 선수들이 "클럽간에"부르는 것 같아요. 어떤 솔루션이 가장 좋을까요?

답변

1

없는 CRTP와 최소한의 예 :

#include <boost/parameter.hpp> 
#include <boost/static_assert.hpp> 

BOOST_PARAMETER_TEMPLATE_KEYWORD(Policy1_is) 
BOOST_PARAMETER_TEMPLATE_KEYWORD(Policy2_is) 

typedef boost::parameter::parameters< 
      boost::parameter::optional<tag::Policy1_is>, 
      boost::parameter::optional<tag::Policy2_is> 
     > PolicySelector; 


struct foo {}; 
struct bar {}; 
struct baz; 
typedef typename PolicySelector::bind<foo, baz>::type Policies; 
boost::parameter::value_type<Policies, tag::Policy1_is, bar>::type x; // <- !!! 

그래서 boost::parameter::value_type은 필기 클래스의 경우에는 해당되지 않습니다 완전한 유형에 따라 할 수있는 정책 선택이 필요합니다.

클래스 자체가 자체 정책으로 필요한 이유는 확실하지 않습니다.

struct CuriousBreadSlicer : BreadSlicer < 
      Policy1_is<CuriousBreadSlicer *> > // <- compiles 

을 또는 당신은 명확성을 위해, 자신의 wrap_incomplete_type<> 템플릿을 사용할 수 있습니다 : 당신이 필요한 경우, 아마 당신은 완전한 뭔가 불완전한 유형을 포장 할 수있다.

정책을 사용할 때 포장 된 것인지 확인할 수 있습니다.

+0

CRTP는 유형 특성에서 오는 ODR을 피하기 위해 사용됩니다. 내 질문에 링크 Alexandrescu에 의해 게시물을 참조하십시오. 본질적으로 정책 클래스는 모든 특수 특성을 표시 할 때 사용됩니다. 포장 아이디어가 좋습니다. 이상적으로는'boost :: parameter :: value_type '에 전달되는'false'가 기본값 인 추가 매개 변수가되어야합니다. – TemplateRex

+0

명명 된 템플릿 인수는 매우 필수적인 것 같습니다 효과적인 정책 기반 프로그래밍 왜 그들이 표준에 포함시키지 않았습니까? – AlwaysLearning