Как совместить идеальную пересылку с инициализаторами в скобках

Этот код компилируется:

pair <pair<int,int>,unique_ptr<int>> t({0,0}, unique_ptr<int>());

Кроме того:

tuple<pair<int,int>,unique_ptr<int>> t(make_pair(0,0), unique_ptr<int>());

Но этот не делает:

tuple<pair<int,int>,unique_ptr<int>> t({0,0}, unique_ptr<int>());

Причина в том, что третий звонит tuple(const Types&...), но это кажется произвольным ограничением.

C ++ 11 не может выразить это с помощью шаблонов с переменным числом аргументов или это возможно?

2

Решение

Это возможно, но не тривиально. Чтобы сделать эту работу, кортеж, содержащий N аргументы должны поддержать 2^N конструкторы, все комбинации T&& а также T const& для каждого T,

Что мы должны сделать, это смешать в них 2^N конструкторы, которые могут быть сделаны с использованием наследования. Поскольку конструкторы базовых классов могут быть доступны только с using В явном виде мы можем добавлять конструкторы только с фиксированным числом базовых классов, поэтому мы должны использовать рекурсию.

Один подход будет рассчитывать от 0 в 2^N и сделать i-й параметр const-ref, если i-ый бит равен 1, или r-значение в противном случае. Сделать это с 2^N Всего базовых классов, где каждый добавляет один конструктор к своей прямой базе.

namespace detail {
// A bitlist holds N powers of two: 1, 2, 4, 8, 16, ...
template <std::size_t... i> struct bitlist { using type = bitlist; };
template <std::size_t N, typename=bitlist<>>
struct make_bitlist;
template <std::size_t N, std::size_t... i>
struct make_bitlist<N, bitlist<i...>>
: make_bitlist<N-1, bitlist<0,1+i...>> {};
template <std::size_t... i> struct make_bitlist<0, bitlist<i...>>
: bitlist<(1<<i)...> {};

struct forward_tag {}; // internal struct that nobody else should use

// if T is a reference, some constructors may be defined twice, so use a non-accessible type.
template <bool B, typename T>
using const_if_set = typename std::conditional<B,
typename std::conditional<std::is_reference<T>::value, forward_tag, T const&>::type, T&&>::type;

// Our helper class.  Each tuple_constructor is derived from N-1 others
// each providing one constructor.  N shall equal (1<<sizeof...(T))-1
template <std::size_t N, typename L, typename... T> struct tuple_constructor;

template <std::size_t N, std::size_t... I, typename... T>
struct tuple_constructor<N, bitlist<I...>, T...>
:  tuple_constructor<N-1, bitlist<I...>, T...>
{ // inherit base constructors
using tuple_constructor<N-1, bitlist<I...>, T...>::tuple_constructor;
tuple_constructor(const_if_set<(N & I), T>... t)
: tuple_constructor<N-1, bitlist<I...>, T...>
(forward_tag{}, std::forward<const_if_set<(N & I), T>>(t)...) {}
};

// base case: N=0, we finally derive from std::tuple<T...>
template <std::size_t... I, typename... T>
struct tuple_constructor<0, bitlist<I...>, T...> : std::tuple<T...> {
tuple_constructor(T&&... t)
: tuple_constructor(forward_tag{}, std::forward<T&&>(t)...) {}

// All constructor calls are forwarded to this one
template <typename... T2>
tuple_constructor(forward_tag, T2&&... t2)
: std::tuple<T...>(std::forward<T2>(t2)...) {}
};

// Convenience using for N=2^n, bitlist=1,2,4,...,2^n where n = sizeof...(T)
template <typename... T>
using better_tuple_base = tuple_constructor
< (1<<sizeof...(T)) - 1, typename make_bitlist<sizeof...(T)>::type,  T... >;
}

template <typename... T> struct better_tuple : detail::better_tuple_base<T...> {
using typename detail::better_tuple_base<T...>::tuple_constructor;
};

Жить на LWS

Но будьте осторожны, это плохо масштабируется для больших кортежей и значительно увеличивает время компиляции. На мой взгляд, это ограничение в языке.

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]