Date: Wed, 27 May 2020 21:03:28 +0800
Compare class declaration with CTAD and function without CTAD:
std::basic_string a("Hello, world!"); // deduce 'a' as
std::basic_string<char, std::char_traits<char>, std::allocator<char> >
template <class CharT, class Traits = std::char_traits<CharT>, class
Allocator = std::allocator<CharT>>
void foo(std::basic_string<CharT, Traits, Allocator> arg); // have to
write all template argument to adapt all 'std::basic_string' type without
CTAD
Badly:
foo(a); // OK: deduce 'CharT' as char
foo("Hello!"); // Error, no match function for call to 'char[7]'
So I have to provides another overload of foo:
template <class CharT>
void foo(const CharT *ptr)
{
foo<CharT>(ptr);
}
More badly, introduce 'std::basic_string_view', change argument type of the
basic function to 'std::basic_string_view', and add a user-defined
deduction guide:
template <class CharT, class Traits = std::char_traits<CharT>, class
Allocator = std::allocator<CharT>>
std::basic_string_view(std::basic_string<CharT, Traits, Allocator>) ->
std::basic_string_view<CharT, Traits>;
template <class CharT, class Traits = std::char_traits<CharT>>
void foo(std::basic_string_view<CharT, Traits, Allocator> arg);
template <class CharT, class Traits = std::char_traits<CharT>, class
Allocator = std::allocator<CharT>>
void foo(std::basic_string<CharT, Traits, Allocator> arg)
{
foo(std::basic_string_view{arg});
}
template <class CharT>
void foo(const CharT *ptr)
{
foo(std::basic_string_view{ptr}); // Can no longer use foo<CharT>
}
Let's apply CTAD to functions, all three template functions can be reduced
to only one CTAD function with a user-defined deduction guide:
template <class CharT, class Traits = std::char_traits<CharT>, class
Allocator = std::allocator<CharT>>
std::basic_string_view(basic_string<CharT, Traits, Allocator>) ->
std::basic_string_view<CharT, Traits>;
void foo(std::basic_string_view arg);
Then just call like this:
const char *ptr = "Hello, ";
std::basic_string sz("world ");
std::basic_string_view sv("CTAD");
foo(ptr); // OK: deduce 'foo' as 'void foo( std::basic_string_view<char,
std::char_traits<char>> ), pass 'ptr' as 'std::basic_string_view{ptr}'
foo(sz); // OK: deduce 'foo' through the user-defined deduction guide,
pass 'sz' as 'std::basic_string_view{sz}'
foo(sv); // OK, of cource
Q&A:
1. Is foo a template function?
A: It's still a template function. CTAD doesn't change a class template
to a normal class, neither did function.
2. How many function template is instantiated in this example?
A: Only one. Depend on std::basic_string_view.
3. How could it be only one?
A: All parameters of three calls construct the same type
'std::basic_string_view<char, std::char_traits<char>>' first. So there's
just only one.
4. What if pass a type which cannot deduce to std::basic_string_view?
A: Error, no match function for call to '<type>'.
std::basic_string a("Hello, world!"); // deduce 'a' as
std::basic_string<char, std::char_traits<char>, std::allocator<char> >
template <class CharT, class Traits = std::char_traits<CharT>, class
Allocator = std::allocator<CharT>>
void foo(std::basic_string<CharT, Traits, Allocator> arg); // have to
write all template argument to adapt all 'std::basic_string' type without
CTAD
Badly:
foo(a); // OK: deduce 'CharT' as char
foo("Hello!"); // Error, no match function for call to 'char[7]'
So I have to provides another overload of foo:
template <class CharT>
void foo(const CharT *ptr)
{
foo<CharT>(ptr);
}
More badly, introduce 'std::basic_string_view', change argument type of the
basic function to 'std::basic_string_view', and add a user-defined
deduction guide:
template <class CharT, class Traits = std::char_traits<CharT>, class
Allocator = std::allocator<CharT>>
std::basic_string_view(std::basic_string<CharT, Traits, Allocator>) ->
std::basic_string_view<CharT, Traits>;
template <class CharT, class Traits = std::char_traits<CharT>>
void foo(std::basic_string_view<CharT, Traits, Allocator> arg);
template <class CharT, class Traits = std::char_traits<CharT>, class
Allocator = std::allocator<CharT>>
void foo(std::basic_string<CharT, Traits, Allocator> arg)
{
foo(std::basic_string_view{arg});
}
template <class CharT>
void foo(const CharT *ptr)
{
foo(std::basic_string_view{ptr}); // Can no longer use foo<CharT>
}
Let's apply CTAD to functions, all three template functions can be reduced
to only one CTAD function with a user-defined deduction guide:
template <class CharT, class Traits = std::char_traits<CharT>, class
Allocator = std::allocator<CharT>>
std::basic_string_view(basic_string<CharT, Traits, Allocator>) ->
std::basic_string_view<CharT, Traits>;
void foo(std::basic_string_view arg);
Then just call like this:
const char *ptr = "Hello, ";
std::basic_string sz("world ");
std::basic_string_view sv("CTAD");
foo(ptr); // OK: deduce 'foo' as 'void foo( std::basic_string_view<char,
std::char_traits<char>> ), pass 'ptr' as 'std::basic_string_view{ptr}'
foo(sz); // OK: deduce 'foo' through the user-defined deduction guide,
pass 'sz' as 'std::basic_string_view{sz}'
foo(sv); // OK, of cource
Q&A:
1. Is foo a template function?
A: It's still a template function. CTAD doesn't change a class template
to a normal class, neither did function.
2. How many function template is instantiated in this example?
A: Only one. Depend on std::basic_string_view.
3. How could it be only one?
A: All parameters of three calls construct the same type
'std::basic_string_view<char, std::char_traits<char>>' first. So there's
just only one.
4. What if pass a type which cannot deduce to std::basic_string_view?
A: Error, no match function for call to '<type>'.
Received on 2020-05-27 08:06:50