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 astd::basic_string_view
. Thesize_type
parameter type in (3) refers to thesize_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?
CodePudding user response:
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>
.
CodePudding user response:
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>
.