2017-10-20 16 views
0

Quelqu'un peut-il expliquer pourquoi cette assertion statique est fausse? Comment redéfinir is_empty pour qu'il fonctionne comme je le souhaite (sans changer la syntaxe)? Un type qui n'est pas un pack que je veux évaluer à false par défaut (par exemple is_empty<int>::value doit être faux).Déterminer si un pack est vide ou non

#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); 
} 

Répondre

2

Le problème est le type T contenu dans Z ne peut pas être déduit.

Fonctionne si vous l'explicite et je ne sais pas comment éviter d'explicite.

#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 si votre Z exigent un premier type d'argument (la manière de std::integer_sequence); De cette façon, la déduction fonctionne

#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-

Dans 17 œuvres C + avec 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); 
} 
+0

Oui, c'était ma solution de rechange, que je dois éviter. Donc, il n'y a aucun moyen de maintenir ma syntaxe? – prestokeys

+0

@prestokeys - autant que je sache, non. Mais je ne suis pas un expert et quelqu'un de mieux que moi peut trouver une solution. Peut-être qu'avec C++ 17 devrait être possible (mais vous avez marqué C++ 11) mais j'échoue également avec lui. – max66

+0

@prestokeys - répond un peu amélioré mais pas exactement ce que vous avez demandé – max66

7

Pourquoi faites-vous cela?

Vous pouvez faire sizeof...(args) pour déterminer la longueur du bloc de paramètres .. S'il est 0, alors il est vide:

#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; 
} 
+0

@ Brandon J'en ai besoin évalué à la compilation. Mais vous m'avez donné quelques idées. – prestokeys

+0

Qu'est-ce qui vous fait penser que 'sizeof ...' n'est pas évalué au moment de la compilation? C'est, tout comme "sizeof". Ainsi, vous pourriez alors créer vos modèles de traits d'une manière plus simple, en utilisant cela. –

+0

@prestokeys 'sizeof ...' est la compilation. Vous pouvez l'utiliser dans static_assert' ou d'autres modèles. http://en.cppreference.com/w/cpp/language/parameter_pack#The_sizeof..._operator – Brandon