2010-03-08 5 views
11

대부분의 C++ 프로그래머는 자유 함수의 부분 템플릿 전문화를 허용하지 않습니다. 그러나자유 함수의 부분 템플릿 전문화 - 모범 사례

template <class T, int N> 
T mul(const T& x) { return x * N; } 

template <class T> 
T mul<T, 0>(const T& x) { return T(0); } 

// error: function template partial specialization ‘mul<T, 0>’ is not allowed 

, 이 허용 클래스/구조체의 부분 템플릿 특수화, 무료 기능의 부분 템플릿 특수화의 기능을 모방하기 위해 이용 될 수있다 : 예를 들어, 다음은 ++ 불법 C입니다. 예를 들어, 마지막 예제에서 대상 목적은 사용에 의해 달성 될 수있다 :

template <class T, int N> 
struct mul_impl 
{ 
    static T fun(const T& x) { return x * N; } 
}; 

template <class T> 
struct mul_impl<T, 0> 
{ 
    static T fun(const T& x) { return T(0); } 
}; 

template <class T, int N> 
T mul(const T& x) 
{ 
    return mul_impl<T, N>::fun(x); 
} 

덜 간결 더 부피가 크고,하지만이 작업을 수행 도착 - 그리고 지금까지 mul의 사용자에 관한 한, 그들이 얻을 원하는 부분 전문화.


내 질문

은 다음과 같습니다 (다른 사람에 의해 사용하기위한 것입니다) 템플릿 무료 기능을 작성할 때 라이브러리의 사용자가 구현할 수 있도록 자동으로 클래스의 정적 메소드 기능 구현을 위임한다 부분적으로 전문화 할 것인가, 아니면 템플릿 화 된 함수를 정상적인 방법으로 작성하고 사람들이 특수화 할 수 없다는 사실에 따라 살고 있습니까?

+2

나는 그것이 달려 있다고 생각한다. 귀하의 경우에는 'fun (u)'와 같이 호출하므로 과부하 ('N '이 매개 변수에 표시되지 않습니다) 할 수 없습니다. 그러나 "오버로딩"이 가능하다면, 그것은 선호되는 방법이라고 생각합니다. 훌륭한 예제는'std :: swap' 또는'std :: begin' 또는'std :: end' (후자의 두 가지는 C++ 0x 함수입니다)입니다. Sutter의 기사는 9 년 전에 작성되었습니다. 그가 여전히 "클래스에 위임 (delegate to class)"방법을 사용하도록 권장하는지 여부는 확실하지 않습니다. ADL에서는 작동하지 않을 것입니다. 모든 종류의 네임 스페이스를 사용하고 템플릿을 전문화해야합니다. 좋지 않음 –

답변

3

litb은 ADL이 템플릿 매개 변수는 호출 매개 변수로부터 추론 할 수 있습니다 때마다 기본적으로 어떤 일을 할 수있는 우수, 말처럼 S = ns::Identity에 대해 arithmetic::mul 함수 템플릿을 부분적으로 특수화하여 달성 한 결과를 얻을 수 있습니다. 하지만 호출자가 ADL을 허용하는 방식으로 전화를 걸기 때문에 호출자는 std::swap을 절대 호출하지 않습니다.

그렇다면 라이브러리 사용자가 함수 템플릿을 부분적으로 특수화해야한다고 생각합니까? 알고리즘 유형을 특수화하려는 경우 (일반적으로 알고리즘 템플릿의 경우처럼) ADL을 사용합니다. 귀하의 예제에서와 같이 정수 템플릿 매개 변수를 특수화하려고한다면 클래스에 위임해야한다고 생각합니다. 그러나 제 3자가 3을 통해 곱셈을해야한다는 것을 제 3자가 정의 할 것을 제 기대하지 않습니다. - 내 라이브러리는 모두 정수를 할 것입니다. 제 3자가 octonion에 의한 곱셈을 정의 할 것을 합리적으로 기대할 수 있습니다.

이 그것을 생각 해 내 arithmetic::muloperator* 혼동을 일으킬 정도로 유사하다는 것, 그래서 내 예제에서 mul을 전문으로하는 실제 필요가 없기 때문에, 지수는 나를 사용을위한 더 나은 예되었을 수 있습니다. 그렇다면 "아무것도의 힘에 대한 정체성은 정체성"때문에 첫 번째 매개 변수에 대해/ADL 과부하를 전문화합니다. 그래도 아이디어를 얻을 수 있기를 바랍니다.

나는 ADL에 단점이 있다고 생각한다. 이것은 네임 스페이스를 효과적으로 평평하게 만든다. ADL을 사용하여 내 수업에 arithmetic::subsandwich::sub을 모두 구현하려는 경우 문제가 발생할 수 있습니다. 나는 전문가가 그것에 대해 무엇을 말해야하는지 모른다.

가하는 말 :

namespace arithmetic { 
    // subtraction, returns the difference of lhs and rhs 
    template<typename T> 
    const T sub(const T&lhs, const T&rhs) { return lhs - rhs; } 
} 

namespace sandwich { 
    // sandwich factory, returns a baguette containing lhs and rhs 
    template<typename SandwichFilling> 
    const Baguette sub(const SandwichFilling&lhs, const SandwichFilling&rhs) { 
     // does something or other 
    } 
} 

지금, 나는 형 ns::HeapOfHam 있습니다.

namespace ns { 
    HeapOfHam sub(const HeapOfHam &lhs, const HeapOfHam &rhs) { 
     assert(lhs.size >= rhs.size && "No such thing as negative ham!"); 
     return HeapOfHam(lhs.size - rhs.size); 
    } 
} 

나는 또한 내 자신의 구현을 작성하는 표준 : : 스왑 스타일 ADL을 활용하려는 : 나는 산술 :: 하위 내 자신의 구현을 작성하는 표준 : : 스왑 스타일 ADL을 활용하려면 샌드위치 :: 하위 :

namespace ns { 
    const sandwich::Baguette sub(const HeapOfHam &lhs, const HeapOfHam &rhs) { 
     // create a baguette, and put *two* heaps of ham in it, more efficiently 
     // than the default implementation could because of some special 
     // property of heaps of ham. 
    } 
} 

잠시만 기다려주십시오. 나는 그것을 할 수 없다, 그렇지? 동일한 매개 변수와 다른 반환 유형을 사용하는 서로 다른 네임 스페이스의 두 가지 함수 : 일반적으로 문제가 아닌 네임 스페이스입니다. 하지만 나는 둘 다 할 수는 없다. 아마도 나는 정말 명백한 것을 놓치고 있습니다.

Btw,이 경우에는 arithmetic::subsandwich::sub을 각각 완전히 전문화 할 수 있습니다. 발신자는 using 중 하나를 선택하고 올바른 기능을 얻습니다. 원래의 질문은 부분 전문화에 관한 것이지만, HeapOfHam을 클래스 템플릿으로 만드는 사실이 없으면 전문화가 옵션이 아닌 것처럼 할 수 있습니까?

+0

평평한 네임 스페이스에 대한 '하위'문제가 확실하지 않습니다. 'sub'가 멤버 함수라면 동일한 문제가 있다고 생각합니다. 그 두 개의 잠수함의 피연산자는 무엇입니까? 만약 샌드위치 : 나는 산술적으로 샌드위치를 ​​서브 할 수있는 방법을 상상할 수 없다. 따라서 산술에 정의 된 '샌드위치'는 불가능 해 보인다. If MyInt : 암시 적 변환이 효과적으로 고려되지 않기 때문에 ('샌드위치'에 치즈 플레이트의 수에 대해 '(MyInt)'가있는 경우) 'sub (a, b)'라고하면, 하위 샌드위치 '물론), 나는 처음에는 문제처럼 보이지 않는다. 네가 이것에 대해 자세히 말하면 나는 기뻐할 것이다. –

+0

@litb : 저는 여러분을 잘 따르지 않으므로 편집하고 우리가 똑같은 것을 말하고 있는지 살펴 보겠습니다. –

+0

@lit : done. 당신이 그 해답을 모른다면 어쩌면 내가 질문 할 것입니다. –

1

다른 곳에 사용하거나 다른 사람들이 사용할 라이브러리를 작성하는 경우 struct/class를 수행하십시오. 더 많은 코드이지만 라이브러리 사용자 (아마도 미래의 여러분!)에게 감사드립니다. 이것이 하나의 사용 코드라면, 부분 전문화의 손실은 당신을 해치지 않을 것입니다.

#include <iostream> 

namespace arithmetic { 
    template <class T, class S> 
    T mul(const T& x, const S& y) { return x * y; } 
} 

namespace ns { 
    class Identity {}; 

    // this is how we write a special mul 
    template <class T> 
    T mul(const T& x, const Identity&) { 
     std::cout << "ADL works!\n"; 
     return x; 
    } 

    // this is just for illustration, so that the default mul compiles 
    int operator*(int x, const Identity&) { 
     std::cout << "No ADL!\n"; 
     return x; 
    } 
} 

int main() { 
    using arithmetic::mul; 
    std::cout << mul(3, ns::Identity()) << "\n"; 
    std::cout << arithmetic::mul(5, ns::Identity()); 
} 

출력 :

ADL works! 
3 
No ADL! 
5 

오버로드 + ADL