2014-01-12 7 views
1

형식 특성에 따라 템플릿 사양 사이에서 컴파일러를 선택할 수 있습니까? 예를 들어, 순차 형식 (strings, vectors, lists 등)과 정수 유형에 대한 두 가지 템플릿 구현을 비교 함수라고 가정합니다. 각 유형의 유형에 대해 하나의 템플리트 특수화 만 가질 수 있습니까?조건에 의해 템플릿 특수화가 제한됨

template <class SeqT> 
class Compare 
{ 
public: 
    bool operator()(const SeqT& s1, const SeqT& s2) const 
    { 
     typename SeqT::const_iterator it1=s1.begin(); 
     typename SeqT::const_iterator it2=s2.begin(); 
     while(it1!=s1.end() && it2!=s2.end()) 
     { 
     if(*it1<*it2) return true; 
     if(*it2<*it1) return false; 
     ++it1; ++it2; 
     } 
     return it2!=s2.end(); 
    } 
}; 

template <class IntegerT> 
class Compare 
{ 
public: 
    bool operator()(IntegerT i1, IntegerT i2) const 
    { 
     return i1<i2; 
    } 
}; 

template <class T, class Cmp = Compare<T> > 
class SomeContainer 
{ 
    ... 
}; 

기본적으로 내가 찾고있는 부분은 템플릿 인수에 조건을 부과하여 부분적으로 템플릿을 특수화하는 방법입니다. 첫 번째 Compare<>과 마찬가지로 std::basic_string<>, std::vector<>, std::list<> 및 두 번째 유형은 int, unsigned, short, char입니다. 그게 가능하니?

+0

예. std :: enable_if를보십시오 – bolov

+0

우선'std :: enable_if'를 생각했습니다. 그러나 유형의 종류를 나타내는 템플릿 매개 변수를 추가하는 것이 더 좋으며 기본 유형에서 "계산 된"TMP가 될 수 있다고 생각합니다. 그런 다음 전문화를 제공하십시오. –

+0

시퀀스로 무엇을 의미합니까? for for (auto x : y) 구문을 사용하여 반복 할 수있는 객체를 의미합니까? – Yakk

답변

2

이것은 다른 질문에 대한 나의 대답이지만, 필요한 것입니다. SFINAE를 사용하여 특정 유형의 Bee와 같은 조건에 대해 true를 테스트하는 템플릿 인수에만 템플릿 전문화를 작성합니다.

https://stackoverflow.com/a/20898554/2805305

편집

그러나 어떻게 정확하게 첫번째 비교 전문화에 적용 할 수 있도록 지정할 수 있습니다 예를 들어, std :: basic_string 및 std :: vector? T는 벡터 또는 basic_string 또는 목록 인 경우

당신은 당신을 알려주는 특성을 만들 : 당신이 다른 유형의 클래스 Compare를 인스턴스화 할 수있게하려면

#include <iostream> 
#include <vector> 
#include <string> 
#include <list> 
#include <complex> 
#include <type_traits> 
using namespace std; 

template <class T> 
struct is_seq : std::false_type { 
}; 

template <class T> 
struct is_seq<std::vector<T>> : std::true_type { 
}; 

template <class T> 
struct is_seq<std::basic_string<T>> : std::true_type { 
}; 

template <class T> 
struct is_seq<std::list<T>> : std::true_type { 
}; 

template <class T> 
using enable_if_seq_type = typename std::enable_if<is_seq<T>::value>::type; 

template <class T> 
using enable_if_integral_type = typename std::enable_if<std::is_integral<T>::value>::type; 


template <class T, class Enable = void> 
class Compare; // <-------- define if you want a Compare for any type that doesn't match any specialization 

template <class T> 
class Compare<T, enable_if_seq_type<T>> { // specialization for T a vector, string or list 
    public: 
     void foo() { 
      cout << "vector, string and list specialization" << endl; 
     } 
}; 

template <class T> 
class Compare<T, enable_if_integral_type<T>> { // specialization for T an integral type 
    public: 
     void foo() { 
      cout << "integral specialization" << endl; 
     } 
}; 


int main() { 
    cout << std::boolalpha; 

    cout << is_seq<int>::value << endl; // false 
    cout << is_seq<std::vector<int>>::value << endl; // true 

    Compare<int> c1; // uses second specialization 
    c1.foo(); // output "integral specialization" 

    Compare<std::vector<int>> c2; // uses first specialization 
    c2.foo(); // output "vector, string and list specialization" 

    //Compare<std::complex<int>> c3; 
    // compile error if you just declare and not define the generic Compare. 
    // If you define the generic Compare, this will compile and it will use 
    // that definition 

    return 0; 
} 

http://ideone.com/JUbwla

첫 번째 (일반) Compare 선언을 정의합니다.

+0

감사합니다. 그러나 첫 번째 비교 전문화를 예를 들어에 적용 할 수 있다고 정확히 지정하려면 어떻게해야합니까? std :: basic_string 및 std :: vector ? 또한 _fail_에 컴파일 할 필요는 없지만 형식 인수가 일부 조건과 일치 할 때 컴파일러가 적절한 템플릿을 _choose_ 지정합니다. 위의 예와 같이 SomeContainer 이 인스턴스화 된 경우 Compare 이 사용되고 SomeContainer 이 인스턴스화 된 경우 Compare 이 사용됩니다. – bkxp

+1

@bkxp 답변을 편집했습니다. – bolov

+1

@bolov 위의 방법에는 문제가 있습니다. 간단한 문제는 비정상적인 할당자를 가진'std :: vector', 기본이 아닌 char 특성을 가진'std :: string' 등이 모두 작동하지 않는다는 것입니다. 근본적인 문제는 일종의 오리 (duck) 유형 테스트와 비교할 때 조건과 일치하는 '템플릿'목록을 유지하는 것이 좋지 않다는 점입니다. – Yakk

관련 문제