1

Source code

This is basically a non-recursive std::tuple_element implementation.

Note: To make this non-recursive, you must replace std::make_index_sequence with a non-recursive implementation. I left it with std::make_index_sequence in order to provide a MVCE.

deduct<std::size_t, T> has a specialization of deduct_impl<T> that is generated from the index sequence template argument it receives. It is used in order to deduce the type at index in a variadic type template or tuple.

itp<std::size_t> and itp<std::size_t, T> is an index-type-pair used to expand the variadic indices template with a type variadic template in order to match the generated specialization.

deducer<std::size_t, T...> puts it all together by specializing deduct<std::size_t, T> and deduct_impl<T> by using std::conditional_t to generate the correct specialization.

Basically, for std::tuple<void, int, char>, in order to get the type at index 1, it creates itp_base<0>, itp<1, int>, itp_base<2> and passes it to deduct and deduct_impl.

#include <iostream>
#include <string>
#include <tuple>

template <std::size_t index>
struct itp_base {};

template <std::size_t index, typename T>
struct itp : itp_base<index> {};

template <std::size_t index, typename IndexSequence>
struct deduct;

template <std::size_t index, std::size_t... indices>
struct deduct<index, std::index_sequence<indices...>>
{
    template <typename Tuple>
    struct deduct_impl;

    template <typename T, typename... R>
    struct deduct_impl<std::tuple<itp_base<indices>..., itp<index, T>, R...>>
    {
        using type = T;
    };
};

template <std::size_t index, typename... Types>
class deducer
{
private:
    static_assert( index < sizeof...( Types ), "deducer::index out of bounds" );

    template <typename IndexSequence>
    struct deducer_impl;

    template <std::size_t... indices>
    struct deducer_impl<std::index_sequence<indices...>>
    {
        using type = typename deduct<index, std::make_index_sequence<index>
        >::template deduct_impl
        <
            std::tuple
            <
                std::conditional_t
                <
                    std::is_base_of<itp_base<indices>, itp<index, Types>>::value,
                    itp<index, Types>,
                    itp_base<indices>
                >...
            >
        >::type;
    };

public:
    using type = typename deducer_impl<
        std::make_index_sequence<sizeof...( Types )>>::type;
};

template <std::size_t index, typename... Types>
using tuple_element_t = typename deducer<index, Types...>::type;

int main()
{
    tuple_element_t<3, int, void, char, std::string> s{ "string" };
    std::cout << s << '\n';
}

Odd compiler behaviour

Clang++

I'm getting warnings for non-deducible template arguments from Clang++, but the program outputs correctly.

Visual C++ v140

The type is detected correctly. However I get the following warning:

warning C4552: '<<': operator has no effect; expected operator with side-effect

The program does not output anything.

G++

Everything works properly.

Demo

http://coliru.stacked-crooked.com/a/7cb3ac06ab4b2d4c

user2296177
  • 2,807
  • 1
  • 15
  • 26
  • @dyp The code is actually detecting the correct type properly in all three compilers, so if it was miswritten, wouldn't it just fail? Either way, there's no deduction actually going on there, because `indices` has already been deduced and is just being expanded. – user2296177 Dec 02 '15 at 08:01
  • Right, I got confused. – dyp Dec 02 '15 at 08:05
  • Side remark: I remember Kurshid having a simpler solution for the `conditional_t` / `is_base_of` part. As far as I can see, it can also be applied here: something like `tuple...>` where `itp` is a `template struct itp;` – dyp Dec 02 '15 at 08:08
  • I think clang emits a false positive warning; MSVC's behaviour seems to be broken. For example, replace your main with a `static_assert( is_same, std::string>::value, "" );` and it complains about this not being a constant expression. – dyp Dec 02 '15 at 08:13
  • @dyp Can you link me to that please? I actually came up with this solution after looking at your answer here: http://stackoverflow.com/a/18594309/2296177 The reason being that I was getting compiler errors about template depth. I know that your solution definitely works on G++ as well. – user2296177 Dec 02 '15 at 08:15
  • Link to what? Kurshid's solution is just below my answer, and I mentioned in a comment to Kurshid's answer that you could replace the `xor` with an `==`. – dyp Dec 02 '15 at 08:18
  • 2
    Oh, and if you need a really efficient version, please take a look at boost.hana and its implementors blog: http://ldionne.com/2015/11/29/efficient-parameter-pack-indexing/ – dyp Dec 02 '15 at 08:19
  • @dyp Sorry, I completely missed his answer. Thanks for that boost.hana link. – user2296177 Dec 02 '15 at 08:20
  • It seems a false positive warning. example can be simplified btw [Demo](http://coliru.stacked-crooked.com/a/9dee59ac5df0d815) – Jarod42 Dec 02 '15 at 09:09

0 Answers0