Can a user refer to a deduced type of a deduction guide?

105 views Asked by At

std::basic_string's deduction guides allow the user to use the std::basic_string name without specifying its template parameters. Users are also allowed to create their own deduction guides. Assume that the user wants to recreate std::basic_string. Sooner or later they will be tasked with implementing deduction guides. However, a note from cppreference makes me wonder whether it is at all possible. The note in question says:

These deduction guides are provided for std::basic_string to allow deduction from a std::basic_string_view. The size_type parameter type in (3) refers to the size_type member type of the type deduced by the deduction guide. These overloads participate in overload resolution only if Alloc satisfies Allocator.

Emphasis mine.

Can a user implement such a requirement? How can a programmer refer to aliases of the deduced type?

2

There are 2 answers

0
Artyer On BEST ANSWER

The "type deduced by the deduction guide" is just the type to the right of the ->:

template< class CharT,
          class Traits,
          class Alloc = std::allocator<CharT>> >
basic_string( std::basic_string_view<CharT, Traits>, typename basic_string<CharT, Traits, Alloc>::size_type,
              typename basic_string<CharT, Traits, Alloc>::size_type, const Alloc& = Alloc() )
    -> basic_string<CharT, Traits, Alloc>;

Seems like it's just a shorthand for writing all the template arguments again, especially in places where the deduced type would be much longer, like unordered_set<typename std::iterator_traits<InputIt>::value_type, std::hash<typename std::iterator_traits<InputIt>::value_type>, std::equal_to<typename std::iterator_traits<InputIt>::value_type>, Alloc>.

5
Marek R On

First see documentation about User-defined deduction guides.

Then take a look on this example:

#include <iostream>
#include <string>
#include <vector>

template<typename T>
class Foo
{
public:
    template<typename C>
    Foo(C) {}

    template<typename C>
    Foo(C, typename C::size_type) {}
};

template<typename C>
Foo(C) -> Foo<typename C::value_type>;

template<typename C>
Foo(C, typename C::size_type) -> Foo<typename C::value_type>;

int main()
{
    std::string s;
    std::vector v{1, 3, 1};

    Foo foo{s}; // Here Foo<char> is used
    static_assert(std::is_same_v<Foo<char>, decltype(foo)>);

    Foo bar{v};
    Foo baz{v, 2};
    static_assert(std::is_same_v<Foo<int>, decltype(bar)>);
    static_assert(std::is_same_v<Foo<int>, decltype(baz)>);
}

https://godbolt.org/z/fsd6aMnY4

As you can see C type is used to guide to actually desired type. You can use something more complex then Foo<typename C::value_type>.