实现具有const正确性的可变参数zip函数

时间:2011-07-09 00:03:01

标签: c++11 reference const-correctness variadic-templates perfect-forwarding

我正在尝试实现zip功能。 zip的参数均为wrapped<Ti>,其中Ti因参数而异。

zip获取这些wrapped<Ti>并生成wrapped<tuple<T1&,T2&,...TN&>>,或者换句话说,包含tuple对其参数的引用。引用应保留const - ness。

这是我第一次使用一个参数刺向zip,这通常不起作用:

#include <utility>
#include <tuple>

// implement forward_as_tuple as it is missing on my system
namespace ns
{

template<typename... Types>
  std::tuple<Types&&...>
    forward_as_tuple(Types&&... t)
{
  return std::tuple<Types&&...>(std::forward<Types>(t)...);
}

}

template<typename T>
  struct wrapped
{
  wrapped(T &&x)
    : m_x(std::forward<T>(x))
  {}

  T m_x;
};

template<typename T>
  wrapped<std::tuple<T&&>>
    zip(wrapped<T> &&x)
{
  auto t = ns::forward_as_tuple(std::forward<T>(x.m_x));
  return wrapped<std::tuple<T&&>>(t);
}

int main()
{
  wrapped<int> w1(13);

  wrapped<int> &ref_w1 = w1;

  // OK
  zip(ref_w1);

  const wrapped<int> &cref_w1 = w1;

  // XXX won't compile when passing a const reference
  zip(cref_w1);

  return 0;
}

有没有办法用zip的单个版本实现一般的,可变的情况?

3 个答案:

答案 0 :(得分:1)

不可否认,我没有处理可变参数模板的C ++ 0x编译器,所以我无法测试它。但这可能会成功。

template<typename T>
    struct wrapped
{
    wrapped(T &&x)
    : m_x(std::forward<T>(x))
    {}

    typedef T type;

    T m_x;
};

template<typename... Types>
    wrapped<std::tuple<Types&&...>> zip(wrapped<Types>&&... x)
{
    return wrapped<std::tuple<Types&&...>>(std::tuple<Types&&...>(std::forward<Types>(x.m_x)...));
}

我不完全确定如此调用zip是否合法:

zip(wrapped<T1>(value1), wrapped<T2>(value2));

您可能必须明确限定通话:

zip<T1, T2>(wrapped<T1>(value1), wrapped<T2>(value2));

答案 1 :(得分:1)

这是我到达的解决方案:

#include <utility>
#include <tuple>
#include <cassert>

template<typename T>
  struct wrapped
{
  wrapped(T &&x)
    : m_x(std::forward<T>(x))
  {}

  T m_x;
};

template<typename Tuple>
  wrapped<Tuple> make_wrapped_tuple(Tuple &&x)
{
  return wrapped<Tuple>(std::forward<Tuple>(x));
}

template<typename... WrappedTypes>
  decltype(make_wrapped_tuple(std::forward_as_tuple(std::declval<WrappedTypes>().m_x...)))
    zip(WrappedTypes&&... x)
{
  return make_wrapped_tuple(std::forward_as_tuple(x.m_x...));
}

int main()
{
  wrapped<int> w1(1);
  wrapped<int> w2(2);
  wrapped<int> w3(3);
  wrapped<int> w4(4);

  auto z1 = zip(w1,w2,w3,w4);

  z1.m_x = std::make_tuple(11,22,33,44);

  assert(w1.m_x == 11);
  assert(w2.m_x == 22);
  assert(w3.m_x == 33);
  assert(w4.m_x == 44);

  const wrapped<int> &cref_w1 = w1;

  auto z2 = zip(cref_w1, w2, w3, w4);

  // does not compile, as desired
  // z2.m_x = std::make_tuple(111,222,333,444);

  return 0;
}

zip取代WrappedTypes...代替wrapped<T>...并不是一个令人满意的解决方案,但它确实有效。

答案 2 :(得分:0)

template<typename T>
    struct wrapped
{
    wrapped(T &&x)
    : m_x(std::forward<T>(x))
    {}

    typedef T type;

    T m_x;
};

template<typename... Types>
    wrapped<std::tuple<T&&...>> zip(wrapped<Types>... &&x)
{
    return G+