나는 다음 클래스를 가지고 기능이 shared_ptr<T>
C++ (11) 방법 템플릿 특수화는
Foo foo;
foo.bar<shared_ptr<int>>();
foo.bar<shared_ptr<long>>();
으로 그러나 물론 호출 될 때 경우에 나는 전체 스펙을 작성하지 않으 각 유형에 대한 초기화. 그러한 행동을 구현할 수 있습니까? (필요한 경우 형질 기반이 될 수 있습니까?)
나는 다음 클래스를 가지고 기능이 shared_ptr<T>
C++ (11) 방법 템플릿 특수화는
Foo foo;
foo.bar<shared_ptr<int>>();
foo.bar<shared_ptr<long>>();
으로 그러나 물론 호출 될 때 경우에 나는 전체 스펙을 작성하지 않으 각 유형에 대한 초기화. 그러한 행동을 구현할 수 있습니까? (필요한 경우 형질 기반이 될 수 있습니까?)
이 하나가 T
구분하는 SFINAE을 사용할 수 있습니다 및 std::shared_ptr<U>
:
template <typename T>
struct is_shared_ptr_impl : std::false_type {};
template <typename T>
struct is_shared_ptr_impl<std::shared_ptr<T>> : std::true_type {};
template <typename T>
using is_shared_ptr = typename is_shared_ptr_impl<typename std::decay<T>::type>::type;
class Foo
{
public:
template <typename T>
auto bar()
-> typename std::enable_if<!is_shared_ptr<T>{}, T>::type
{
std::cout << "T is " << typeid(T).name() << std::endl;
return {};
}
template <typename T>
auto bar()
-> typename std::enable_if<is_shared_ptr<T>{}, T>::type
{
using U = typename std::decay<T>::type::element_type;
std::cout << "T is shared_ptr of " << typeid(U).name() << std::endl;
return {};
}
};
확실히 여러 가지 방법이 있습니다. 내 마음에 오는 첫 번째 방법은 단순히 함수 오버로딩입니다. 오버로드 할 매개 변수가 없으므로 매개 변수를 만들어야합니다. 포인터를 좋아하는데, 이는 함수에 유형을 전달하는 방법으로 효과적으로 작용합니다.
class Foo {
//regular overload
template<typename T>
T bar(T*) { //takes a pointer with an NULL value
cout << "Called with return type: " << typeid(T).name() << endl;
T t = //... (some implementation here)
return t;
}
//shared_ptr overload - NOTE THAT T IS THE POINTEE, NOT THE SHARED_PTR
template<typename T>
std::shared_ptr<T> bar(std::shared_ptr<T>*) { //takes a pointer with an null value
cout << "Called with return type: " << typeid(T).name() << endl;
std::shared_ptr<T> t = //... (some implementation here)
return t;
}
public:
template <typename T>
T bar() {
T* overloadable_pointer = 0;
return bar(overloadable_pointer);
}
};
나는 주위 종류를 전달하는 포인터를 사용하여 다른 사람이 들어, 그래서이 작업을 수행하도록 선택하는 경우, 안전을 위해 철저하게 언급 없어요. 은 wierd 코드입니다.
템플릿 기능을 수행하기 위해 단순히 도우미 구조체를 사용하는 것이 더 직관적 일 수 있습니다. 이는 대부분의 사람들이하는 일입니다. 불행하게도 Foo
(아마도 그렇게 할 것임) 멤버에게 액세스해야하는 경우 템플릿 전문화를 사용하려면 모든 멤버를 함수에 전달하거나 템플릿 도우미를 친구로 초대해야합니다. 양자 택일로, 당신은 다른 멤버에게 type_traits 전문화를 전달할 수 있지만, 단순히 위의 포인터 트릭의 복잡한 버전이됩니다. 많은 사람들이 더 정상적이고 덜 혼동 스럽다는 것을 알게되었으므로 다음과 같습니다.
template<typename T>
struct Foo_tag {};
class Foo {
//regular overload
template<typename T>
T bar(Foo_tag<T>) {
}
//shared_ptr overload - NOTE THAT T IS THE POINTEE, NOT THE SHARED_PTR
template<typename T>
std::shared_ptr<T> bar(Foo_tag<std::shared_ptr<T>>) {
}
public:
template <typename T>
T bar() {
return bar(Foo_tag<T>{});
}
}
재미있는 방법입니다. – 0x499602D2
실제로, 나는 그것에게 시도를 줄 것이다 :) – Daimon
왜 "정의되지 않은 값"? 값은 0 ... 당신은 그 이름이 바르지 않다는 것을 의미합니까? – Barry
기능을 부분적으로 특수화 할 수 없습니다. 이유에 대한 이야기는 GOTW에서 확인하십시오.
당신 이 부분적으로하지만 클래스를 전문으로 할 수 있습니다, 그래서 당신은 무엇을 할 수 있는지입니다 :
template <typename T>
T bar() {
return bar_impl<T>::apply(this);
}
여기서 아무도 아직 그것을 제안하기 때문에
template <typename T>
struct bar_impl {
static T apply(Foo*) {
// whatever
}
}
template <typename T>
struct bar_impl<std::shared_ptr<T>> {
static std::shared_ptr<T> apply(Foo*) {
// whatever else
}
}
0x499602D2 코멘트 후에 내 마음에 온 해결책이 될 것 같습니다. 또한 Mooing Duck의 대답보다 조금 덜 "해킹 된"것처럼 보입니다 – Daimon
@Daimon 필자는 필연적으로 "hacky"라고 부를 것입니다. 나는 그것을 본 적이 한번도 없다 - 그리고 그것은 적어도 두 가지 장점을 제공한다. (1) 모든 Foo 코드가 Foo에있다. (2) Foo의 private 멤버에게 우정없이 접근 할 수있다. 내 것은 이것을 더 많이 받아 들일 수있는 일반적인 방법 일뿐입니다. – Barry
우정에 관한. bar_impl을 Foo의 내부 클래스로 만들 수 없습니까? 이것은 우정을 자동으로 만들어야하며 내부적으로 구현을 유지해야합니까? – Daimon
기능 템플릿은 부분적으로 특수화 할 수 없지만 클래스 템플릿은 할 수 있습니다. 공용 정적 멤버 함수를 노출하고 부분적으로 클래스를 특수화하고 멤버 함수를 적절하게 변경하는 래핑 클래스 템플릿을 만듭니다. – 0x499602D2