Jul 6, 2022

[C++20] std::type_identity for Non-deduced contexts

Reference:
https://vsdmars.blogspot.com/2018/05/caccu2018-tricks-library-implementation.html


While reading {fmt} code:
https://github.com/fmtlib/fmt/blob/e6d478f8e88a357671c39bd39922ecac32aa2f58/include/fmt/core.h#L3107

template <typename... Args>
using format_string = basic_format_string<char, type_identity_t<Args>...>;
wondering why is type_identity_t needed?

This is due to how arguments participate function parameter deduction.

This is sort of template deduction 101, i.e. for parameters there's no implicit conversion involved.

Thus in order to avoid ambiguity from the deduction rule imposed on compiler,
introducing a Non-deduced contexts which uses the deduced type explicitly(which avoids implicit conversion at compile time) to remove ambiguity and allow implicit conversion at runtime.

e.g.
// the identity template, often used to exclude specific arguments from deduction
// (available as std::type_identity as of C++20)
template<typename T>
struct identity { typedef T type; };
 
template<typename T>
void bad(std::vector<T> x, T value = 1);
 
template<typename T>
void good(std::vector<T> x, typename identity<T>::type value = 1);
 
std::vector<std::complex<double>> x;
 
bad(x, 1.2);  // P1 = std::vector<T>, A1 = std::vector<std::complex<double>>
              // P1/A1: deduced T = std::complex<double>
              // P2 = T, A2 = double
              // P2/A2: deduced T = double
              // error: deduction fails, T is ambiguous
 
good(x, 1.2); // P1 = std::vector<T>, A1 = std::vector<std::complex<double>>
              // P1/A1: deduced T = std::complex<double>
              // P2 = identity<T>::type, A2 = double
              // P2/A2: uses T deduced by P1/A1 because T is to the left of :: in P2
              // OK: T = std::complex<double>

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.