2011-02-27 2 views
6

나는 보통 내 클래스와 템플릿을 선언 한 다음 (같은 헤더 파일에서) 메소드를 정의합니다. 나는 그 방법을 읽기가 더 쉽다. 글쎄, 클래스 밖의 정의에 사용할 작업 형식 서명을 파악할 수없는 경우를 발견했습니다. 여기에 내가 뭘하는지의 간단한 예입니다, 그게 문제 보여enable_if'ed 템플릿 템플릿 생성자의 유형 시그니처입니까?

template <class T> 
struct Foo 
    { 
    Foo(T a, T b); 

    template 
     < class Iterator 
     , enable_if< is_iterator<Iterator> > 
     > 
    Foo 
     (Iterator first 
     , Iterator last 
    ); 
    }; 

template <class T> 
Foo<T>::Foo(T a, T b) 
{ ... } 

template <class T> 
template 
    < class U 
    , WHAT_GOES_HERE? 
    > 
Foo<T>::Foo(U f, U l) 
{ ... } 

내가 일치하는 서명을 얻으려고하는 WHAT_GOES_HERE 슬롯에 여러 가지를 시도, 그리고 나는 계속 실패. 하나의 T가 두 객체에 전달되는 경우와 한 쌍의 반복자에서 전달되는 경우를 구별하기 위해 enable_if가 필요합니다. 이 코드는 템플릿 생성자가 기본 템플릿 내부에 정의되어있는 경우 코드가 올바르게 작동하지만 코드가 현재 수행하는 방식이지만 선언 외부에서 정의를 이동하는 것이 좋습니다.

편집 : enable_if < ...이> 당신이 할 수없는 그 유형에 대한 기본 값을 할당하기 때문에 나는, 정의에> ... < enable_if 난 그냥 수 없음을 다시 사용을 언급해야한다 선언이 아닌 정의.

+1

당신이 정말이에 대한 SFINAE가 필요하십니까? 두 번째 생성자를 'template Foo (U first, U last);'로 선언 한 경우, 호출자가'T '유형의 두 객체를 전달하면 첫 번째 생성자가 여전히 선택됩니다. –

+0

타입 T는 일반적으로 산술 타입이며 T가 부호가없고 그 반대의 경우 int에 전달할 수 있고 템플릿 생성자가 호출되지 않도록하고 싶습니다 (이전에 enable_if를 사용하기 전에 발생했습니다) – swestrup

+0

실제로, 당신은 기본값을 전혀 지정하지 않습니다. 템플릿의 두 번째 매개 변수는'enable_if >'입니다. 당신이'int'를 기대하는 것과 같습니다. 그것은 컴파일되지 않아야하며 확실히 사용할 수 없습니다. –

답변

3

나는 그렇게하지 않을 것입니다. 여기에 내가 만드는 것이 변화는 다음과 같습니다

template <class T> 
struct Foo 
    { 
    Foo(T a, T b); 

    template 
     < class Iterator 
     > 
    Foo 
     (Iterator first 
     , Iterator last 
     , typename enable_if<is_iterator<Iterator> >::type* = 0 
    ); 
    }; 

template <class T> 
Foo<T>::Foo(T a, T b) 
{ ... } 

template <class T> 
template 
    < class U 
    > 
Foo<T>::Foo(U f, U l, typename enable_if< is_iterator<U> >::type*) 
{ ... } 

이 바로 enable_if에 대한 문서를 벗어났습니다.

+0

흥미 롭다면, 나는 여러 번 enable_if 문서를 읽었으며, 중첩 된 함수로 생성자를 다루는 일은 결코 일어나지 않았습니다 ... 이것이 작동한다면, 확실히 받아 들일 수 있습니다. – swestrup

+0

http://www.boost.org/doc/libs/1_46_0/libs/utility/enable_if를 참조하십시오.html 섹션 3 : "생성자와 소멸자에는 반환 유형이 없으므로 추가 인수가 유일한 옵션입니다." –

+0

감사! 그것은 실제로 트릭을했습니다. 즉, 이전에 시도했던 것은 불가능했기 때문에 C++을 만족시키는 형식 시그니처를 제공 할 방법이 없다는 것입니다. – swestrup

2

달성하려는 목표입니까? [is_iterator 형질 특성이 없으므로 C++ 0x 유형 특성 및 유틸리티 라이브러리를 사용하여 예제를 수정했습니다. 그것은 TR1과 Boost 라이브러리와 같은 방식으로 작동해야합니다.]

#include <utility> 
#include <type_traits> 

template <typename T> 
struct S 
{ 
    // Constructor (1) 
    S(T, T); 

    // Constructor (2) 
    template <typename U> 
    S(U, U, typename std::enable_if<std::is_integral<U>::value>::type* = 0); 
}; 

template <typename T> 
S<T>::S(T, T) 
{ } 

template <typename T> 
template <typename U> 
S<T>::S(U, U, typename std::enable_if<std::is_integral<U>::value>::type*) 
{ } 

int main() 
{ 
    S<double> a(1.0, 2.0); // uses (1) 
    S<double> b(1, 2);  // uses (2) 
} 
+0

그래, 다소 정확하다. 나 자신의 is_iterator를 써야했다. 나는 왜 그것이 표준이 아닌지 잘 모른다. – swestrup

1

당신이 할 수있는 가장 간단한은 다음과 같습니다

template<class Iterator> 
Foo 
    (Iterator first 
    , typename enable_if<is_iterator<Iterator>, Iterator>::type last 
); 
1
template <class T> 
struct Foo 
    { 
    Foo(T a, T b); 

    template <class Iterator 
     ,  class = typename std::enable_if 
         <is_iterator<Iterator>::value> 
         ::type 
     > 
    Foo 
     (Iterator first 
     , Iterator last 
    ); 
    }; 

template <class T> 
Foo<T>::Foo(T a, T b) 
{ } 

template <class T> 
template 
    < class U 
    , class > 
Foo<T>::Foo(U f, U l) 
{ } 
+0

나는 이것을 시도했지만 작동하지 않는다. 정의가 내 템플릿의 선언과 일치하지 않는다는 메시지가 나타납니다. , 나는 말해야한다, ** ** 일해야한다! – swestrup

+0

나는 g ++ - 4.4와 clang으로 테스트했다. 그러나 나는 테스트를 위해 -std = C++ 0x를 가졌지 만 이제는 다시 체크해야한다고 생각합니다. 그것이 없다면 경고 메시지가 나타납니다 : 경고 : 함수 템플릿의 기본 템플릿 인수는 C++ 0x 확장입니다 [-WC++ 0x-extensions] , class = typename std :: enable_if –

+0

이상한 예제가 작동합니다. 나는 내 컴파일러로 시도해 본다. 하지만 실제 템플릿에서 똑같은 작업을 시도하면 오류가 발생합니다. 나는 틀린 일을해야만합니다 ... – swestrup