2013-11-14 2 views
4

는 다음과 같은 템플릿 함수를 고려 다른 컨테이너에서 smart_pointer를 분별하기 specilization을 호출하여 올바른 함수가 호출되도록합니다. 다음 운전 코드는 예상대로 작동 : 이제템플릿 기능은

vector<int> v {1,2}; 
DoSomething(v); 

우리는 우리가 컴파일 오류를 얻을 : 우리가 이것을 시도하는 경우

char r('r'); 
DoSomething(r); 
DoSomething(&r); 
shared_ptr<char> s(new char ('s')); 
unique_ptr<char> u(new char ('u')); 
DoSomething(s); 
DoSomething(u); 

그러나, 어떤 일이 발생하는 지 생각해 봅시다. 컴파일러가 사용하기로 결정한 DoSomething의 버전은 네 번째 버전입니다. 이 안에서 우리는 벡터에없는 get() 함수를 참조합니다. 컴파일러가 어떻게 든 DoSomething의 첫 번째 정의를 선택한다면 컴파일이 잘되고 의도대로 작동합니다.

템플릿 템플릿 매개 변수에 get() 메서드가 포함되어있을 때만 3 번째 및 4 번째 전문화가 일치하도록 제한 할 수 있습니까? 어쩌면 특성, SFINAE 또는 다른 고급 템플릿 기술을 사용하여 이런 일이 발생할 수있는 방법이 있습니까?

+2

여기에가는 전형적인 방법은 SFINAE입니다. – leemes

답변

4

컴파일러가 사용하기로 결정한 DoSomething 버전은 네 번째 버전입니다.

std::vector<T, std::allocator<T>>는 템플릿 매개 변수 containerstd::allocator<T> 정확히 일치하는 템플릿 매개 변수 deleter에 정확히 일치하며, const container<T, deleter<T>>&const T& 그렇게 4 과부하가 부분적인 순서에 의해 가장 일치로 선택보다 더 전문이기 때문에 기능 템플리트에 대한 규칙.

템플릿 템플릿 매개 변수에 get() 메소드가 포함되어있을 때만 3 번째 및 4 번째 전문화가 일치하도록 제한 할 수 있습니까? 인수 T가로 대체 할 수 없기 때문에, t.get()하면

template <class T, template <class> class container> 
auto DoSomething(const container<T>& t) -> decltype(t.get()) 
{ 
    auto& type_id = typeid(T); 
    auto& container_id = typeid(container<T>); 
    cout << "Type is " << type_id.name() << ", and we have a "; 
    cout << container_id.name() << "of one\n"; 
    return t.get(); 
} 

다음 템플릿 인수 공제가 실패 유효한 표현되지 않습니다 :

예, 함수가 반환 어떤 t.get() 반환 컴파일러를 알 수 있습니다 함수 서명이 성공적으로 실행되므로 함수가 실행 가능한 오버로드가 아니며 대신 첫 번째 오버로드가 사용됩니다.

+0

그것은 SFINAE에게는 매우 영리한 방법입니다. 나는 노트를 추가하고 싶습니다 : 만약't'가 또 다른 메소드를 사용할 수 있다고 가정한다면 (일반적으로 메소드가 필요하다면 = 리턴 표현식),'set (int)'라고 가정 해 봅시다.'- > decltype (t.set (std :: declare ()), t.get())'. – leemes

+0

정말 멋집니다. 나는 이보다 훨씬 더 복잡한 것을해야 할 것으로 예상했다. 감사. –

+0

사실, SO를 위해 구운 예제는 내가 필요로하는 것이 아닙니다. 내 코드에는 실제로 DoSomething 함수의 반환 유형이 없으므로 사용자가 설명하는 것을 정확히 수행 할 수 없습니다. 필자는 leemes가 제안하는 것을 시도하고있다. -> decltype (t.get(), void) 그러나 이것은 컴파일되지 않는다 –

2

나는이 시도 것 :이 같은

template <typename> 
struct is_smart : ::std::false_type 
{ 
}; 

template <typename T> 
struct is_smart<::std::shared_ptr<T> > : ::std::true_type 
{ 
}; 

사용 :

::std::cout << is_smart<container<T> >{} << ::std::endl; 

하지만 오히려 이런 식으로 무시할 것 : 모든 컨테이너와 스마트 포인터

template <class T> 
T* DoSomething(const ::std::shared_ptr<T>& t) 
{ 
} 

지원하려는 유형.

+0

답장을 보내 주셔서 감사합니다.이 코드를 나와 통합하는 방법에 대한 팁이 있습니까? –

+0

스트림에 'bool'을 쓰는 것이 올바른 오버로드를 어떻게 도울 수 있습니까? –

+0

다른 'T'에 대해 '1'과 '0'을 보는 것이 도움이됩니다. – user1095108

2

영업 코드는 사용자 정의 Deleter가있는 표준 :: unique_ptr을 사용하는 결함이 있습니다

struct Deleter { 
    void operator()(char*) const {} 
}; 

unique_ptr<char, Deleter> u(new char ('u'), Deleter()); 
DoSomething(u) // The first is applied. 

오리 입력을 사용 SFINAE를 통해이 문제가된다.

template <typename T, typename U> 
struct X { 
    // Is this a get like a get of a smart pointer !? 
    T* get(); 
} 

해결 방법은 user1095108입니다.

+0

예, 스키마의 약점을 지적했습니다. 확실히 shared_ptr과 unique_ptr에 명시 적 오버로드를 사용하는 것이 장점입니다. –

+0

커스텀 deleter의 문제는'template class deleter'와 일치하는 것뿐만 아니라 어떤 deleter도 허용하도록 4th overload를 변경함으로써 쉽게 해결할 수 있습니다. 그러나 다른 문제를 야기 할 수 있으며, 주된 포인트는 좋은 것입니다 –