Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determining if a pack is empty or not

Can someone explain why this static assertion is false? How to redefine is_empty so that it works the way I want it to (without changing the syntax)? A type that is not a pack I want to evaluate to false by default (e.g. is_empty<int>::value shall be false).

#include <type_traits>
template <typename Pack> struct is_empty : std::false_type {};

template <typename T, template <T...> class Z, T... Is>
struct is_empty<Z<Is...>> : std::true_type {};

template <typename T, template <T...> class Z, T First, T... Rest>
struct is_empty<Z<First, Rest...>> : std::false_type {};

template <int...> struct Z;

int main() {
    static_assert(is_empty<Z<>>::value);
}
like image 690
prestokeys Avatar asked Oct 27 '25 13:10

prestokeys


2 Answers

Why do you do that?

You can do sizeof...(args) to determine the length of the parameter pack.. If it is 0, then it is empty:

#include <iostream>

template<typename... Args>
void func(Args... args)
{
    std::cout<<(sizeof...(args));
}

int main() {

    func(1, 2, 3);
    func();
    func(1);
    func(1, 2);
    func(1, 2, 3, 4);

    return 0;
}
like image 97
Brandon Avatar answered Oct 30 '25 03:10

Brandon


The problem is the type T contained in Z can't be deduced.

Works if you explicit it and I don't know how to avoid to explicit.

#include <type_traits>

template <typename...>
struct is_empty : std::false_type
 { };

template <typename T, template <T...> class Z, T... Is>
struct is_empty<T, Z<Is...>> : std::true_type
 { };

template <typename T, template <T...> class Z, T First, T... Rest>
struct is_empty<T, Z<First, Rest...>> : std::false_type
 { };

template <int...> struct Z;

int main() {
    static_assert(is_empty<int, Z<>>::value, "!");
}

-- EDIT --

Works if your Z require a first argument type (in the way of std::integer_sequence); in this way the deduction works

#include <type_traits>

template <typename>
struct is_empty : std::false_type
 { };

template <typename T, template <typename U, U...> class Z, T... Is>
struct is_empty<Z<T, Is...>>
   : std::integral_constant<bool, sizeof...(Is) == 0U>
 { };

template <typename T, T ...>
struct X
 { };

template <int ... Is>
using Y = X<int>;

int main ()
 {
   static_assert(is_empty<X<int>>::value, "!");
   static_assert(is_empty<Y<>>::value, "!");
 }

-- EDIT 2 --

In C++17 works with auto

#include <type_traits>

template <typename Pack>
struct is_empty : std::false_type
 { };

template <template <auto...> class Z, auto... Is>
struct is_empty<Z<Is...>> : std::bool_constant<sizeof...(Is) == 0U>
 { };

template <int...>
struct X;

int main()
 {
   static_assert( true  == is_empty<X<>>::value );
   static_assert( false == is_empty<X<1>>::value );
   static_assert( false == is_empty<int>::value );
 }
like image 41
max66 Avatar answered Oct 30 '25 05:10

max66