Re: How to implement std::tuple's sometimes std::pair constructor?
On 2013-08-02 09:53, Daryle Walker wrote:
I think that std::tuple has a constructor like:
template < typename ...Types >
struct tuple
{
//...
// Only valid when sizeof...(Types) == 2
template < typename T, typename U >
tuple( std::pair<T, U> p );
//...
};
Is there a way to implement that besides having it in a (partial)
specialization when there are two parameters and omitting it for all
other specializations?
This is indeed very easily possible (and I don't think that there exist
a real std::tuple implementation in the wild which would use partial
specialization).
I'm thinking about adding constructors like
these in a class template of mine, but I don't want to write a bunch of
otherwise-identical specializations.
If you only want to impose constraint upon the size, this can be solved
like this:
template <class U1, class U2,
typename std::enable_if<std::tuple_size<my_tuple>::value == 2,
bool>::type = false
>
my_tuple(const std::pair<U1, U2>&);
I'm assuming here that std::tuple_size is specialized for your type
my_tuple. If not, replace std::tuple_size by a type-dependent template
such as
template<class... Args>
constexpr std::size_t pack_size()
{
return sizeof...(Args);
}
and write it like this:
template <class U1, class U2,
typename std::enable_if<pack_size<Types...>() == 2, bool>::type = false
>
my_tuple(const std::pair<U1, U2>&);
(The introduction of either std::tuple_size or pack_size() ensures that
the sfinae test condition is type-dependent, which is currently needed)
If you want to impose further constraints that should be imposed
element-wise, there is no need for the extra-constraint upon sizes, it
can often be done implicitly. Consider the following example given the
following utility templates (useful elsewhere as well)
template<std::size_t I, class Tuple, bool = I <
std::tuple_size<Tuple>::value>
struct nth_type_impl
{
typedef typename std::tuple_element<I, Tuple>::type type;
};
template<std::size_t I, class Tuple>
struct nth_type_impl<I, Tuple, false>
{
typedef void type;
};
template<std::size_t Index, class... Ts>
using nth_type = typename nth_type_impl<Index, std::tuple<Ts...>>::type;
template<class...>
struct and_;
template<>
struct and_<> : std::true_type {};
template<class P>
struct and_<P> : P {};
template<class P1, class P2>
struct and_<P1, P2> : std::conditional<P1::value, P2, P1>::type {};
template<class P1, class P2, class P3, class... Pn>
struct and_<P1, P2, P3, Pn...> : std::conditional<P1::value, and_<P2,
P3, Pn...>, P1>::type {};
Now you can for example impose the following constraints:
template <class U1, class U2,
typename std::enable_if<
and_<
std::is_convertible<const U1&, nth_type<0, Types...>>,
std::is_convertible<const U2&, nth_type<1, Types...>>
>::value
, bool>::type = false
>
my_tuple(const std::pair<U1, U2>&);
Depending on your exact use-case even simpler ways exist.
HTH & GReetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]