Почему руководство по выводам классов не работает при использовании typedef?
В фрагменте кода, который я сейчас пишу, я использую руководство по выбору классов. Вы можете найти фрагмент кода, сокращенный до простого (но бессмысленного примера) ниже: У меня есть классUser
, который получает свой первый параметр шаблона из первого аргумента конструктора, а второй - из размера пакета параметров, предоставленного в качестве второго аргумента:
#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};
}
Это отлично работает (компилируется). Когда я вношу крошечные изменения, заменяя тип пакета параметров типом, который зависит от параметра шаблонаswitcher
однако вычет не выполняется:
#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:
}
Это почему?
Оба варианта кода можно найти здесь.
1 ответ
Ваше руководство по выводу во втором примере эквивалентно тому, что мы получаем, заменяя псевдоним:
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>;
В любом синтаксисе typename A::B
где A
зависимый тип, тип A
- невыведенный контекст. посколькуpn
появляется только в невыведенном контексте, он никогда не может быть выведен, так что руководство по дедукции никогда не может быть использовано.
По той же причине конструктор User
никогда не может использоваться с более чем одним аргументом, даже если аргументы шаблона для User
явно указаны.