简体   繁体   中英

Why does the class deduction guide fail when using a typedef?

In a piece of the code I currently write I make use of a class deduction guide. You can find the excerpt of the code stripped down to a simple (but meaningless example) below: I've got a class User , which derives its first template parameter from the constructor's first argument, and the second one from the size of the parameter pack provided as second argument:

#include <cstddef>
#include <type_traits>

/// First constructor parameter, which can be used in order to derive the boolean
template <int, bool switcher> struct P1 {};

/// Class which depends on the boolean flag (from first parameter) and the amount of elements provided.
template <bool switcher, size_t amountKids> struct User {
  template <int p1, int... pn> explicit constexpr User(P1<p1, switcher> &child,
      P1<pn, switcher>... parents) noexcept {}
};

/// Deduction guide
template <bool f, int p1, int... pn> User(P1<p1, f> &child, P1<pn, f> ...) ->User<f, sizeof...(pn) + 1>;

int main() {
  P1<1, true> child;
  User sa{child, P1<1, true>{}};
  User sa2{child, child, child};
}

This works fine (compiles). When I make a tiny modification by replacing the parameter pack's type by a type that depends on the template parameter switcher however, the deduction fails:

#include <cstddef>
#include <type_traits>

/// First constructor parameter, which can be used in order to derive the boolean
template <int, bool switcher> struct P1 {};

/// In the real example, conditional_type holds a different type, depending on the #bool
template <bool, typename T> struct conditional_type { using type = T; };
template <bool switcher, typename T> using conditional_type_t = typename conditional_type<switcher, T>::type;

template <bool switcher, size_t amountKids> struct User {
  template <int p1, int... pn> explicit constexpr User(P1<p1, switcher> &child,
      conditional_type_t<switcher, P1<pn, switcher>>... parents) noexcept {}
};

template <bool f, int p1, int... pn> User(P1<p1, f> &child, conditional_type_t<f, P1<pn, f>>...) ->User<f, sizeof...(pn) + 1>;

int main() {
  conditional_type_t<true, P1<1, true>> child2;
  P1<1, true> child;
  static_assert(std::is_same_v<decltype(child), decltype(child2)>);

  User sa{child, P1<1, true>{}}; //< fails: 2 arguments provided, expecting one, can't derive amountKids
  User sa2{child, child, child}; //< fails: 
}

Why is that?

Both variants of the code can be found here .

Your deduction guide in the second example is equivalent to what we get substituting the alias:

template <bool f, int p1, int... pn>
User(P1<p1, f> &child, typename conditional_type<f, P1<pn, f>>::type ...)
    -> User<f, sizeof...(pn) + 1>;

In any syntax typename A::B where A is a dependent type, the type A is a non-deduced context . Since pn only appears in a non-deduced context, it can never be deduced, so that deduction guide can never be used.

For a similar reason, the constructor of User can never be used with more than one argument, even if template arguments for User are explicitly specified.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM