Hi everybody. 

I've been following the  work on P1858 and just yesterday it occurred to me that it'd be useful to do something like this:

template <typename... Ts>
struct Interface
{
    rtype<Ts> func(ptype<Ts>) ... = 0;
};

template <typename... Ts>
struct Implementation: Interface<Ts...>
{
    rtype<Ts> func(ptype<Ts> p) override
    {
        return impl<Ts>(p);
    } ...
};

where rtype<>, ptype<> and impl<> are fictional templates with exposition-only purpose. 

At the moment such a construct is possible via recursive inheritance, with much added boilerplate and unneeded RTTI information being written out in the resulting binary (for the intermediate, not used types).  Following is a possible implementation of the above, given the current tools at our disposal.

template <typename... Ts>
struct Interface;

template <>
struct Interface<> 
{ };

template <typename T>
struct Interface<T> 
{
    virtual rtype<T> func(ptype<T>) = 0;
};

template <typename T, typename... Ts>
struct Interface<T, Ts...>: Interface<Ts...> 
{
    using Interface<Ts...>::func;
    virtual rtype<T> func(ptype<T>) = 0;
};

namespace detail {

    template <typename Interface, typename... Ts>
    struct Implementation;
    
    template <typename Interface>
    struct Implementation<Interface>: Interface 
    { };
    
    template <typename Interface, typename T>
    struct Implementation<Interface, T>: Interface 
    {
        using Interface::func;            
        rtype<T> func(ptype<T> p) override
        {
            return impl<T>(p);
        }
    };

    template <typename Interface, typename T, typename... Ts>
    struct Implementation<Interface, T, Ts...>: Implementation<Interface, Ts...> 
    {
        using Implementation<Interface, Ts...>::func;
        rtype<T> func(ptype<T> p) override
        {
            return impl<T>(p);
        }
    };

}

template <typename... Ts>
using Implementation = detail::Implementation<Interface<Ts...>, Ts...>;

An alternative version of the above can be implemented with the help of std::variant, but with the limitation that all rtype<Ts>... must be the same, and with the speed penalty that a sub optimized variant can incur. Here's a possible implementation:

template <typename... Ts>
struct Interface
{ 
    using variant_type = std::variant<ptype<Ts>...>;
    using return_type = std::tuple_element_t<0, std::tuple<rtype<Ts>...>>;
    
    static_assert(std::conjunction_v<std::is_same<return_type, rtype<Ts>>...>, "return types must be the same for all functions. Sigh.");
    
    virtual return_type func(variant_type const &) = 0;
};

template <typename... Ts>
struct Implementation: Interface<Ts...>
{ 
    using Interface<Ts...>::variant_type;
    using Interface<Ts...>::return_type;
    
    return_type func(variant_type const &v) override
    {
        return std::visit([](auto p){ return impl<decltype(p)>(); }, v);
    }
};

template <>
struct Interface<>
{ };

template <>
struct Implementation<>: Interface<>
{ };
At the moment I'm using the std::variant approach in some production code, for it's less verbose than the recursive approach and I can cope with its limitations, but I believe it'd be nice to use the generalized pack syntax for that.

All the above considered, I'd therefore like to suggest an amendment to P1858 as described in the first code snippet. 

Fabio Alemagna