如何避免一直编写std :: reference_wrapper版本模板?

时间:2016-12-28 07:41:53

标签: c++ c++11 templates

我有一个函数模板来回应类中的内容,例如:

template<typename T>
void say(const std::vector<T>& ts)
{
    for (const auto& t : ts) {
        std::cout<<t.getDesc()<<std::endl;
    }
}

class Base
{
public
    Base();
    const std::string& getDesc() const {
        return m_desc;
    }
protected:
    std::string m_desc;
}

Base继承的所有对象都可以使用模板函数。

std::vector<Base> v;
Base a;
v.push_back(a)

但是当我转向std::reference_wrapper时,功能模板不起作用。我应该写另一个模板来解决它。

template<typename T>
void say(const std::vector<std::reference_wrapper<T>>& ts)
{
    for (const auto& t : ts) {
        std::cout<<t.get().getDesc()<<std::endl;
    }
}

它们之间的唯一区别是std::reference_wrapper::get()

那么还有其他方法可以避免这个恼人的代码吗?或者我应该为我使用的所有函数编写std :: reference_wrapper版本模板吗?

2 个答案:

答案 0 :(得分:3)

你不需要重写整个事情。只需使用一个间接级别。

namespace detail {
  template<typename T>
  constexpr T& get(T &t) { return t; }

  template<typename T>
  constexpr T const& get(T const &t) { return t; }

  template<typename T>
  constexpr T& get(std::reference_wrapper<T> rt) { return rt; }
}

template<typename T>
void say(const std::vector<T>& ts)
{
    for (const auto& t : ts) {
        std::cout<< detail::get(t) <<std::endl;
    }
}

detail命名空间中的上述函数当然可以重用(虽然可以更好地命名),并且可以使所有模板与std::reference_wrapper一起使用。

答案 1 :(得分:1)

您可以使用帮助Unwrap模板,例如boost::unwrap_reference。或编写自己的,复制此other answer

中的代码
template< typename T >
struct UnwrapReference;

template< typename T >
struct UnwrapReference { typedef T type; }

template< >
struct UnwrapReference< std::reference_wrapper< T > > { typedef T type; }

现在你可以编写一个版本的函数来绑定它们(未经测试):

template<typename T>
void say(const std::vector<T>& ts)
{
    for (const UnwrapReference<T>::type &t : ts) {
        std::cout<<t.getDesc()<<std::endl;
    }
}