我上课了:
class Foo {
public:
template <typename T>
T bar() {
cout << "Called with return type: " << typeid(T).name() << endl;
T t = //... (some implementation here)
return t;
}
}
以下列方式调用:
Foo foo;
int i = foo.bar<int>();
long l = foo.bar<long>();
现在我希望在使用shared_ptr<T>
Foo foo;
foo.bar<shared_ptr<int>>();
foo.bar<shared_ptr<long>>();
但我当然不想为每种类型创建完整的专业化。是否有可能实现这种行为(如果需要可以基于特质)?
答案 0 :(得分:8)
您不能部分专门化功能。有关原因的故事,请查看此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
}
}
答案 1 :(得分:6)
当然有很多方法可以做到。我想到的第一种方式就是函数重载。由于您没有重载参数,因此您必须制作一个参数。我喜欢指针,它有效地将类型传递给函数。
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);
}
};
我从来没有听说过其他人使用指针来传递类型,所以如果你选择这样做,请彻底评论,以确保安全。 是奇怪的代码。
简单地使用辅助结构来进行模板特化可能更直观,这是大多数人会做的事情。不幸的是,如果您需要访问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>{});
}
}
答案 2 :(得分:4)
由于还没有人提出,可以使用SFINAE来区分T
和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 {};
}
};