C ++ 함수 템플릿 부분 전문화?
아래 코드가 클래스의 부분적인 전문화라는 것을 알고 있습니다.
template <typename T1, typename T2>
class MyClass {
…
};
// partial specialization: both template parameters have same type
template <typename T>
class MyClass<T,T> {
…
};
또한 C ++에서는 함수 템플릿 부분 전문화를 허용하지 않습니다. 하지만 내 코드는 하나 / 동일한 유형 인수에 대해 함수 템플릿을 부분적으로 전문화했음을 의미합니까? Microsoft Visual Studio 2010 Express에서 작동하기 때문입니다! 아니라면 부분 전문화 개념을 설명해 주시겠습니까?
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
template <typename T1, typename T2>
inline T1 max (T1 const& a, T2 const& b)
{
return a < b ? b : a;
}
template <typename T>
inline T const& max (T const& a, T const& b)
{
return 10;
}
int main ()
{
cout << max(4,4.2) << endl;;
cout << max(5,5) << endl;
int z;
cin>>z;
}
이 예제에서는 실제로 함수를 오버로딩 (전문화하지 않음) 하고 max<T1,T2>
있습니다. 일부 전문의 구문은 봤어야 다소 (아래처럼 이 허용 예시 )
//Partial specialization is not allowed by the spec, though!
template <typename T>
inline T const& max<T,T> (T const& a, T const& b)
{ ^^^^^ <--- specializing here
return 10;
}
[참고 : 함수 템플릿의 경우 C ++ 표준에서 전체 전문화 만 허용됩니다 (컴파일러 확장 제외).]
답변에서 지적 다른했듯이 부분 전문화는 허용되지 않으므로 아래와 같이 std::is_same
및 을 사용하여 해결할 수 std::enable_if
있습니다.
template <typename T, class F>
inline typename std::enable_if<std::is_same<T, int>::value, void>::type
typed_foo(const F& f) {
std::cout << ">>> messing with ints! " << f << std::endl;
}
template <typename T, class F>
inline typename std::enable_if<std::is_same<T, float>::value, void>::type
typed_foo(const F& f) {
std::cout << ">>> messing with floats! " << f << std::endl;
}
int main(int argc, char *argv[]) {
typed_foo<int>("works");
typed_foo<float>(2);
}
다수 :
$ ./a.out
>>> messing with ints! works
>>> messing with floats! 2
편집 : 남은 다른 모든 케이스를 처리 할 수 있어야하는 경우 이미 처리 된 케이스가 일치 하지 않습니다. 개체 모호한 정의에 빠집니다. 정의는 다음과 가변적입니다.
template <typename T, class F>
inline typename std::enable_if<(not std::is_same<T, int>::value)
and (not std::is_same<T, float>::value), void>::type
typed_foo(const F& f) {
std::cout << ">>> messing with unknown stuff! " << f << std::endl;
}
int main(int argc, char *argv[]) {
typed_foo<int>("works");
typed_foo<float>(2);
typed_foo<std::string>("either");
}
다음을 생성합니다.
$ ./a.out
>>> messing with ints! works
>>> messing with floats! 2
>>> messing with unknown stuff! either
이 모든 경우 가 약간 지루해 보이지만 이미 수행 한 모든 작업을 컴파일러에게 알려야 최대 5 개 또는 몇 가지 전문화를 처리하는 것이 가능합니다.
전문화 란 무엇입니까?
템플릿을보고 이해하고있는 함수형 언어를보고보고합니다. C ++의 템플릿 세계는 순전히 기능적인 자체 하위 언어입니다.
기능적 언어에서는 패턴 일치를 사용하여 선택합니다 .
-- An instance of Maybe is either nothing (None) or something (Just a)
-- where a is any type
data Maybe a = None | Just a
-- declare function isJust, which takes a Maybe
-- and checks whether it's None or Just
isJust :: Maybe a -> Bool
-- definition: two cases (_ is a wildcard)
isJust None = False
isJust Just _ = True
당신이 볼 수 있습니다, 우리는 오버로드 의 정의를 isJust
.
음, C ++ 클래스 템플릿은 똑같은 방식으로 작동합니다. 변수의 수 매개와 특성을 나타내는 기본 선언을 제공합니다 . 선언 일 수도 있고 정의 역할도 할 수있는 경우 (원하는 경우) 패턴의 전문화를 제공하고 다른 (그렇지 명명 된 어리석은) 버전의 클래스와 수 있습니다. .
템플릿 함수의 경우 전문화는 다소 어색합니다. 오버로드 해결과 다소 충돌합니다. 전문화는 비전이 해결되지 않습니다. 따라서 올바른 기능을 선택하는 알고리즘은 다음과 같습니다.
- 일반 기능 및 비전문 템플릿간에 향상된 해결 수행
- 특수화되지 않은 템플릿을 선택한 경우 더 잘 일치하는 전문화가 있는지 확인하십시오.
(심층 치료에 내 GotW # 49 참조 )
따라서 기능의 템플릿 전문화는 문자 그대로 두 번째 영역 시민입니다. 내가 생각하는 한, 우리는 존재 없이는 더 나을 것입니다. 나는 아직 템플릿 전문화 사용이 오버로딩으로 해결 될 수없는 경우를 만나지 될.
템플릿 전문화입니까?
아니요, 등장 인 것은 괜찮습니다. 실제 오버로드는 일반적으로 예상대로 작동하지만 전문화는 놀라 울 수 있습니다 (제가 링크 한 GotW 기사를 기억하십시오).
비 클래스, 비가 변 부분 전문화는 허용되지 않지만 다음과 같다.
컴퓨터 과학의 모든 문제는 다른 수준의 간접적 인 방법으로 수 있습니다. —— 데이비드 휠러
함수 호출을 전달하기 위해 클래스를 추가하면 문제를 해결할 수 있습니다. 예는 다음과 가변적입니다.
template <class Tag, class R, class... Ts>
struct enable_fun_partial_spec;
struct fun_tag {};
template <class R, class... Ts>
constexpr R fun(Ts&&... ts) {
return enable_fun_partial_spec<fun_tag, R, Ts...>::call(
std::forward<Ts>(ts)...);
}
template <class R, class... Ts>
struct enable_fun_partial_spec<fun_tag, R, Ts...> {
constexpr static R call(Ts&&... ts) { return {0}; }
};
template <class R, class T>
struct enable_fun_partial_spec<fun_tag, R, T, T> {
constexpr static R call(T, T) { return {1}; }
};
template <class R>
struct enable_fun_partial_spec<fun_tag, R, int, int> {
constexpr static R call(int, int) { return {2}; }
};
template <class R>
struct enable_fun_partial_spec<fun_tag, R, int, char> {
constexpr static R call(int, char) { return {3}; }
};
template <class R, class T2>
struct enable_fun_partial_spec<fun_tag, R, char, T2> {
constexpr static R call(char, T2) { return {4}; }
};
static_assert(std::is_same_v<decltype(fun<int>(1, 1)), int>, "");
static_assert(fun<int>(1, 1) == 2, "");
static_assert(std::is_same_v<decltype(fun<char>(1, 1)), char>, "");
static_assert(fun<char>(1, 1) == 2, "");
static_assert(std::is_same_v<decltype(fun<long>(1L, 1L)), long>, "");
static_assert(fun<long>(1L, 1L) == 1, "");
static_assert(std::is_same_v<decltype(fun<double>(1L, 1L)), double>, "");
static_assert(fun<double>(1L, 1L) == 1, "");
static_assert(std::is_same_v<decltype(fun<int>(1u, 1)), int>, "");
static_assert(fun<int>(1u, 1) == 0, "");
static_assert(std::is_same_v<decltype(fun<char>(1, 'c')), char>, "");
static_assert(fun<char>(1, 'c') == 3, "");
static_assert(std::is_same_v<decltype(fun<unsigned>('c', 1)), unsigned>, "");
static_assert(fun<unsigned>('c', 1) == 4, "");
static_assert(std::is_same_v<decltype(fun<unsigned>(10.0, 1)), unsigned>, "");
static_assert(fun<unsigned>(10.0, 1) == 0, "");
static_assert(
std::is_same_v<decltype(fun<double>(1, 2, 3, 'a', "bbb")), double>, "");
static_assert(fun<double>(1, 2, 3, 'a', "bbb") == 0, "");
static_assert(std::is_same_v<decltype(fun<unsigned>()), unsigned>, "");
static_assert(fun<unsigned>() == 0, "");
예를 들어 합법적으로 전문화 std::swap
할 수 있지만 자신의 과부하를 합법적으로 정의 할 수는 없습니다. 즉, std::swap
사용자 정의 클래스 템플릿에 대해 작업 할 수 없습니다 .
오버로딩과 부분 전문화는 경우에 따라 동일한 효과를 가질 수 있지만 모두와는 거리가 멀습니다.
늦은 답변이지만 일부 늦은 독자는 유용하다고 생각할 수 있습니다. 때로는 특수화 될 수 있도록 설계된 도우미 기능도 문제를 해결할 수 있습니다.
그래서 상상해 봅시다. 이것이 우리 가 해결 하려고 한 것입니다.
template <typename R, typename X, typename Y>
void function(X x, Y y)
{
R* r = new R(x);
f(r, y); // another template function?
}
// for some reason, we NEED the specialization:
template <typename R, typename Y>
void function<R, int, Y>(int x, Y y)
{
// unfortunately, Wrapper has no constructor accepting int:
Wrapper* w = new Wrapper();
w->setValue(x);
f(w, y);
}
좋아요, 부분 템플릿 함수 전문화, 우리는 그렇게 할 수 없습니다 ... 그래서 전문화에 필요한 부분을 도우미 함수로 "내보내고"그 부분을 전문화하고 사용합시다 :
template <typename R, typename T>
R* create(T t)
{
return new R(t);
}
template <>
Wrapper* create<Wrapper, int>(int n) // fully specialized now -> legal...
{
Wrapper* w = new Wrapper();
w->setValue(n);
return w;
}
template <typename R, typename X, typename Y>
void function(X x, Y y)
{
R* r = create<R>(x);
f(r, y); // another template function?
}
이것은 특히 대안 (전문화 대신 정상적인 오버로드, Rubens가 제안한 해결 방법 ... – 이것이 나쁘거나 내 것이 더 낫다는 것이 아니라 다른 것)가 상당히 많은 공통 코드를 공유 할 경우 흥미로울 수 있습니다 .
참고 URL : https://stackoverflow.com/questions/8061456/c-function-template-partial-specialization
'ProgramingTip' 카테고리의 다른 글
SQL Server ORDER BY 날짜 및 마지막 null (0) | 2020.11.01 |
---|---|
MongoDB는 _id 배열에서 어디를 선택합니까? (0) | 2020.11.01 |
'cd-'는 무엇을 의미합니까? (0) | 2020.11.01 |
대체 분할 오류의 원인은 무엇입니까? (0) | 2020.11.01 |
Tkinter 텍스트 상자 위젯에서 입력을 얻는 방법은 무엇입니까? (0) | 2020.11.01 |