C++ Logo

std-proposals

Advanced search

Apply CTAD features from C++17 to argument type of functions

From: Stay Elite <myh344233108_at_[hidden]>
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>'.

Received on 2020-05-27 08:06:50