A non-recursive tuple_element implementation
Your approach on finding the nth element relies on being able to construct a tuple with the first n-1 types being some predictable thing that you can match against. But the types you chose for std::tuple&lt;void, int, char&gt; were, for index 1, std::tuple&lt;itp_base&lt;0&gt;, itp&lt;1, int&gt;, itp_base&lt;2&gt;&gt;. 

But we don't actually need to introduce this itp thing to do this, we can simply turn it into std::tuple&lt;void, int, void&gt;. That way, deduct_impl's specialization instead of taking a std::tuple&lt;itp_base&lt;indices&gt;..., itp&lt;index, T&gt;, R...&gt;, we can simplify to:

template &lt;std::size_t&gt;
using make_void = void;

template &lt;typename T, typename... R&gt;
struct deduct_impl&lt;std::tuple&lt;make_void&lt;indices&gt;..., T, R...&gt;&gt;
{
    using type = T;
};


And on the other side, we pass in:

std::tuple&lt;std::conditional_t&lt;(indices == index), Types, void&gt;...&gt;


Same idea, just more direct.

For that matter, we don't even need the tuple! std::tuple is an expensive type to construct at compile-time, so it's best to avoid it entirely. Just pass in the types as a pack (though the following doesn't compile on gcc - though even there you don't need tuple, just use a light wrapper like template &lt;class...&gt; struct typelist;)

template &lt;typename... Ts&gt;
struct deduct_impl;

template &lt;std::size_t&gt;
using make_void = void;

template &lt;typename T, typename... R&gt;
struct deduct_impl&lt;make_void&lt;indices&gt;..., T, R...&gt;
{
    using type = T;
};


and:

using type = typename deduct&lt;index, std::make_index_sequence&lt;index&gt;
&gt;::template deduct_impl
&lt;
    std::conditional_t&lt;(indices == index), Types, void&gt;...
&gt;::type;


A different approach

Another non-recursive way to do this would be through an inheritance tree. We basically take std::tuple&lt;void, int, char&gt; and turn it into a type that inherits from indexed&lt;0, void&gt;, indexed&lt;1, int&gt;, and indexed&lt;2, char&gt;:

template &lt;std::size_t I, typename T&gt;
struct indexed {
    using type = T;
};

template &lt;typename Is, typename ...Ts&gt;
struct indexer;

template &lt;std::size_t ...Is, typename ...Ts&gt;
struct indexer&lt;std::index_sequence&lt;Is...&gt;, Ts...&gt;
: indexed&lt;Is, Ts&gt;...
{};


Then, given a function template constrained on an index, we can pull out the correct type:

template &lt;std::size_t I, typename ...Ts&gt;
struct at_index {
private:
    template &lt;typename T&gt;
    static indexed&lt;I, T&gt; select(indexed&lt;I, T&gt;);

    using impl = indexer&lt;std::index_sequence_for&lt;Ts...&gt;, Ts...&gt;;
public:
    using type = typename decltype(select(impl{}))::type;
};


I don't know which solution is better, but this one is certainly shorter.