Во втором случае вы просите, чтобы компилятор соответствовал пакетам внутри отдельных типов (есть пара кортежей Ts1
и кортеж Ts2
). Это определенно однозначно.
В первом примере оба пакета используются в одном пакете параметров, разделенных третьим типом. Я понимаю, почему вы ожидаете, что это сработает, но, очевидно, компилятор (и gcc, и clang) отказывается полностью соответствовать пакетам с префиксом.
В вашем конкретном случае это на самом деле неоднозначно в нескольких случаях: поскольку V является параметром, он также может быть равен 0, что делает его неоднозначным для соответствия последовательности d0
. Во всяком случае, я пытался, что даже использование постоянной 1 не решает проблему. Вам придется удалить префикс самостоятельно.
#include <type_traits>
template<class, int> struct dummy{};
template<class...> struct multiple{};
template<class T, class = void> // <-- was this supposed to be an enabler?
struct exactly_one_not_0 : std::false_type {};
template<class Ts, class...RTs, int V>
struct exactly_one_not_0
<
multiple
<
dummy<Ts, V>,
dummy<RTs, 0>...
>,
std::enable_if_t<V!=0>
> : std::bool_constant<V>
{};
template<class LT, class...RDummies>
struct exactly_one_not_0
<
multiple
<
dummy<LT, 0>,
RDummies...
>
> : exactly_one_not_0<multiple<RDummies...>>
{};
template<class T>
constexpr bool exactly_one_not_0_v = exactly_one_not_0<T>::value;
using d0 = dummy<int,0>;
using d1 = dummy<int,1>;
static_assert(exactly_one_not_0_v<multiple<d1>>);
static_assert(exactly_one_not_0_v<multiple<d1,d0>>);
static_assert(exactly_one_not_0_v<multiple<d0,d1>>);
static_assert(exactly_one_not_0_v<multiple<d0,d1,d0>>);
static_assert(!exactly_one_not_0_v<multiple<>>);
static_assert(!exactly_one_not_0_v<multiple<d0>>);
static_assert(!exactly_one_not_0_v<multiple<d0,d0>>);
static_assert(!exactly_one_not_0_v<multiple<d1,d1>>);
static_assert(!exactly_one_not_0_v<multiple<d0,d1,d1>>);
static_assert(!exactly_one_not_0_v<multiple<d1,d0,d1>>);
static_assert(!exactly_one_not_0_v<multiple<d1,d1,d0>>);
int main()
{
return 0;
}
Ради того, чтобы не создавать несколько multiple
s, вы можете также удалить это
template<class T>
struct exactly_one_not_0 : std::false_type {};
template<class Enable, class... Ts> // <-- was this supposed to be an enabler?
struct exactly_one_not_0_impl : std::false_type {};
template<class... Ts>
struct exactly_one_not_0<multiple<Ts...>>
: exactly_one_not_0_impl<void, Ts...>
{};
template<class Ts, class...RTs, int V>
struct exactly_one_not_0_impl
<
std::enable_if_t<V!=0>,
dummy<Ts, V>,
dummy<RTs, 0>...
> : std::bool_constant<V>
{};
template<class LT, class...RDummies>
struct exactly_one_not_0_impl
<
void,
dummy<LT, 0>,
RDummies...
> : exactly_one_not_0_impl<void, RDummies...>
{};