2010-01-22 6 views
6

C++ 0x에 가변 유효 템플릿의 매개 변수 팩에 특정 유형이 포함되어 있는지 확인하는 기본 제공 기능이 있는지 궁금합니다. 오늘날 boost ::: mpl :: contains는 boost :: mpl :: vector를 variadic 템플릿의 대체물로 사용하는 경우이를 수행하는 데 사용할 수 있습니다. 그러나 컴파일 시간에 심각한 오버 헤드가 있습니다. C++ 0x에는 std :: is_same에 대한 컴파일러 수준의 지원이 있다고 가정합니다. 그래서 아래의 일반화가 컴파일러에서도 지원된다고 생각하고있었습니다. 이 가변 인자 템플릿에 대해 하나 다른 고유 작업을하고C++ 0x 매개 변수 팩에 유형이 포함되어 있는지 확인하십시오.

#include <type_traits> 

template < typename Tp, typename... List > 
struct contains : std::true_type {}; 

template < typename Tp, typename Head, typename... Rest > 
struct contains<Tp, Head, Rest...> 
: std::conditional< std::is_same<Tp, Head>::value, 
    std::true_type, 
    contains<Tp, Rest...> 
>::type {}; 

template < typename Tp > 
struct contains<Tp> : std::false_type {}; 

즉이다 :

template <typename... Args, typename What> 
struct is_present 
{ 
    enum { value = (What in Args...)? 1 : 0 }; 
}; 

답변

3

아니, 당신은 컴파일시이 같은 계산을 수행하는 가변 인자 템플릿 (부분) 전문화를 사용해야합니다

template < typename... Types > 
struct typelist_len 
{ 
    const static size_t value = sizeof...(Types); 
}; 

와 "는 심각한 컴파일 타임 오버 헤드가"당신이 점점 : 매개 변수 목록의 예의 길이를 계산 sizeof의 연산자의 특별한 형태 mpl을에서 밀어 올리시겠습니까? 당신이 여기서 가정을하고 있지 않기를 바랍니다. Boost mpl은 게으른 템플릿 인스턴스화와 같은 기법을 사용하여 순진한 템플릿 메타 프로그래밍처럼 폭발하는 대신 컴파일 타임을 줄이고 시도합니다.

+0

언어/컴파일러가 sizeof .... (4 도트)보다 더 큰 내장 연산을 지원해야합니다. IMO는 크기를 찾는 것과 같이 "기본"이라고 판단합니다. mpl은 필자가 작성한이 테스트를 바탕으로 성능 오버 헤드가 있다고 생각합니다. http://www.dre.vanderbilt.edu/~sutambe/files/mpl_intersection.cpp MPL의 버전뿐만 아니라 손으로 코딩 한 교차 알고리즘을 사용하고 있습니다. g ++ 4.4는 둘 다 컴파일하는데 같은 시간이 걸립니다. Variadic 템플릿 버전은 10 배 빠르게 컴파일됩니다. BTW, 제발 mpl의 게으른 템플릿 인스턴스화 기술에 대한 독서 좀 제안 해 주시겠습니까? – Sumant

+0

C++ Template Metaprogramming 서적에서 게으른 평가의 좋은 예를 발견했습니다. 그게 분명하지 않니?! 어쨌든 고마워. – Sumant

+0

네가해야 할 일은 다른 중첩 메타 함수에 결과를주기 전에 메타 함수의 템플릿 인스턴스화 (중첩 된 유형 별명 유형을 표시하여)를 피하는 것입니다. 부스트 메타 함수는 메타 함수를 평가하도록 설계되었습니다 마지막 순간에 중첩 된 유형의 별칭이 필요합니다. 느린 작업도하도록 설계되었으므로 베어 값을 피하고 메타 데이터 유형 래퍼 (예 : mpl :: bool_)를 사용해야합니다. 가끔씩 boost mpl이 제공합니다. 두 가지 형태의 메타 함수는 게으른 인스턴스화를 촉진하는 것을 사용하려고 시도합니다. –

2

수동 유형 재귀를 피하려면 가변적 인 템플릿 인 STL에서 std::common_type이 유일한 유틸리티 인 것처럼 보입니다. 따라서 재귀를 잠재적으로 캡슐화 할 수있는 유일한 유틸리티입니다.


용액 1

std::common_type는 타입들의 세트 내의 적어도 유래 유형을 발견한다. 유형이있는 숫자, 특히 파생되지 않은 유형이 많은 높은 숫자를 식별하면 세트에서 가장 큰 숫자를 찾습니다. 그런 다음 키 유형에 대한 동등성을 파생 수준에 매핑해야합니다.

using namespace std; 

struct base_one { enum { value = 1 }; }; 
struct derived_zero : base_one { enum { value = 0 }; }; 

template< typename A, typename B > 
struct type_equal { 
typedef derived_zero type; 
}; 

template< typename A > 
struct type_equal< A, A > { 
typedef base_one type; 
}; 

template< typename Key, typename ... Types > 
struct pack_any { 
enum { value = 
    common_type< typename type_equal< Key, Types >::type ... >::type::value }; 
}; 


우리는 common_type 좀 더 해킹 할 수 2

솔루션. 표준은 전문의 적어도 하나 개의 템플릿 매개 변수가 사용자 정의 유형 인 경우 프로그램이이 특성을 전문으로 할 수

말한다.

내부적으로 정확하게 재사용 가능한 부분 전문화 케이스, 2 진 연산자를 적용하는 케이스 및 터미널 케이스를 설명합니다. 본질적으로 그것은 일반적인 fold 함수이고, 당신이 원하는 모든 바이너리 연산을 추가 할 수 있습니다. 여기에 OR을 사용하는 것보다 유익하기 때문에 추가를 사용했습니다. is_sameintegral_constant을 반환합니다.

template< typename Addend > 
struct type_sum { // need to define a dummy type to turn common_type into a sum 
    typedef Addend type; 
}; 

namespace std { // allowed to specialize this particular template 
template< typename LHS, typename RHS > 
struct common_type< type_sum<LHS>, type_sum<RHS> > { 
    typedef type_sum< integral_constant< int, 
    LHS::type::value + RHS::type::value > > type; // <= addition here 
}; 
} 

template< typename Key, typename ... Types > 
struct pack_count : integral_constant< int, 
common_type< type_sum< is_same< Key, Types > > ... >::type::type::value > {}; 
+0

이것은 꽤 두뇌 티저입니다. 그러나 나는 그것을 좋아했다! common_type 특성을 잘 이해하고 있다고 가정합니다. C++ 0x public 초안에서 그것을 파 내야했습니다. 이를 type_equal을 통해 base_one에 암시 적으로 변환하면 영리합니다. C++에는이 똑똑한 트릭이 너무 많습니다. std :: is_same 및 logical을 사용하여보다 직관적 인 작업을 수행 할 수 있습니까? – Sumant

+0

@ 수만 : 네 : v). – Potatoswatter

+0

그것은 다소 나아졌지만 여전히 마음이 마비되는 세부 사항은 내면화되어야합니다. – Sumant

관련 문제