返回类型的C ++ 11方法模板特化

时间:2014-11-13 18:16:40

标签: c++ templates c++11 template-specialization specialization

我上课了:

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>>();

但我当然不想为每种类型创建完整的专业化。是否有可能实现这种行为(如果需要可以基于特质)?

3 个答案:

答案 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来区分Tstd::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 {};
    }
};

DEMO