9

Q1 : Are user-defined deduction guides allowed at namespace scope ?

In the example here, GCC and Clang does not produce the same behavior :

#include <tuple>

template <typename T>
struct some_type;
template <template <typename...> typename T, typename ... Ts>
struct some_type<T<Ts...>>
{
    template <typename U>
    class nested
    {
        U member;
    public:
        nested(U &&){}
    };

    // non-namespace scope user-deduction-guide : OK with Clang, fix the deduction issue
    template <typename U>
    nested(U&&) -> nested<U>;
};

void func()
{
    using pack_type = std::tuple<int, char>;
    some_type<pack_type>::nested{
        [](auto &&){}
    };
}

In short, we have a template-parametered type, with a nested type which is itself template-parametered, and template parameters have no relationship between each others.

template <typename T>
struct some_type;
template <template <typename...> typename T, typename ... Ts>
struct some_type<T<Ts...>>
{
    template <typename U>
    class nested // <- nested type, where `U` as no relationship with `T<Ts...>`
    {
        U member;
    public:
        nested(U &&);
    };
};

The standard specify : http://eel.is/c++draft/temp.deduct.guide#3

[...] A deduction-guide shall be declared in the same scope as the corresponding class template and, for a member class template, with the same access. [...]

Q2 : If no to Q1, what is the syntax to create a user-defined deduction guide for nested type, when there is no relationship between namespace-type and nested-type template-parameters ?

I'd expect a syntax close to :

template <template <typename...> typename T, typename ... Ts>
template <typename U>
some_type<T<Ts...>>::nested<U>::nested(U&&) -> nested<U>;

However, nested<U> is wrong, as it required a deduced type ... to deduce it.

Also, this is interpreted as a function with trailing return type void.

template <template <typename...> typename T, typename ... Ts>
template <typename U>
typename some_type<T<Ts...>>::template nested<U>::nested(U&&) -> nested<U>;

Thanks for your time.

Guss
  • 762
  • 4
  • 20

1 Answers1

1

Quick-fix

The only work-around I found is to add a user-defined deduction guide only for Clang,
which is way sub-optimal in term of maintainability.

Live example on godbolt,
or see the sources below.

Why ?

  • GCC does not allow deduction guide in non-namespace context, Clang does.
  • Clang requires a deduction guide in this context, GCC does not

NB : As posting this, clang trunk is 11.0.1 and gcc trunk is 10.2

#include <tuple>

template <typename T>
struct type
{
    template <typename U>
    struct nested
    {
        template <typename ... nested_Ts>
        nested(U &&, std::tuple<nested_Ts...> &&)
        {}

    };
    #if __clang__
    // here, user-defined deduction guide only for Clang
    template <typename U, typename ... Ts>
    nested(U&&, std::tuple<Ts...>&&) -> nested<U>;
    #endif
};

void instanciate_symbols()
{
    using type = type<int>;
    [[maybe_unused]] auto value = type::nested{'a', std::tuple{42, .42f}};
}
Guss
  • 762
  • 4
  • 20
  • 1
    Do you know if there's been any progress, or will be? I'm still interested in this. If you can't nest the deduction guide, there should really be another way to define it, but I can't figure it out. I was trying all kinds of combinations like `template template typename A::template B(T &&...)`, etc. but no such luck. I would sooner go back to functions like `make_tuple` for the ADL to avoid diverging code. – John P Mar 12 '22 at 03:22