2017-08-17 1 views
0

Supposons que j'ai un tableau d'entiers qui peut grossir avec le temps. Pour économiser de la mémoire, j'ai construit une classe qui prend une valeur maximale qui sera stockée dans le tableau, et la convertit en l'un des types entiers suivants: uint8_t, uint16_t, uint32_t, uint64_t.La sélection du type d'int avec la méta-programmation génère une erreur

Le code:

#include <limits> 
#include <cstdint> 

template <uint64_t MAX_VAL> 
class SELECTOR_INT 
{ 
private: 

    using enum_type = uint64_t; 

    static enum : enum_type { success_8 = 1, success_16 = 2, success_32 = 3, success_64 = 4 }; 
    static enum : enum_type { failure_8 = 11, failure_16 = 12, failure_32 = 13, failure_64 = 14 }; 

    #define TYPE_MAX(_TYPE) static_cast<enum_type>(std::numeric_limits<_TYPE>::max()) 
    static enum : enum_type { result_8 = (         (MAX_VAL <= TYPE_MAX(uint8_t))) ? success_8 : failure_8 }; 
    static enum : enum_type { result_16 = ((MAX_VAL > TYPE_MAX(uint8_t)) && (MAX_VAL <= TYPE_MAX(uint16_t))) ? success_16 : failure_16 }; 
    static enum : enum_type { result_32 = ((MAX_VAL > TYPE_MAX(uint16_t)) && (MAX_VAL <= TYPE_MAX(uint32_t))) ? success_32 : failure_32 }; 
    static enum : enum_type { result_64 = ((MAX_VAL > TYPE_MAX(uint32_t))         ) ? success_64 : failure_64 }; 
    #undef TYPE_MAX 

    #define MIN(_LOP, _ROP) ((_LOP < _ROP) ? _LOP : _ROP) 
    static enum : enum_type { RESULT = MIN(result_8, MIN(result_16, MIN(result_32, MIN(result_32, result_64)))) }; 
    #undef MIN 

private: 

    template <enum_type num> 
    struct CHOOSED; 

    template <> struct CHOOSED <success_8 > { using TYPE = typename uint8_t; }; // Line 162 
    template <> struct CHOOSED <success_16> { using TYPE = typename uint16_t; }; // Line 163 
    template <> struct CHOOSED <success_32> { using TYPE = typename uint32_t; }; // Line 164 
    template <> struct CHOOSED <success_64> { using TYPE = typename uint64_t; }; // Line 165 

public: 

    using TYPE = CHOOSED<RESULT>::TYPE; 

}; 

using int_type = SELECTOR_INT<200>::TYPE; 

int main() 
{ 
    int_type test_variable = 0; 
    return 0; 
} 

malheureusement, j'ai foiré quelque chose parce que je reçois les erreurs suivantes:

1>D:/Dev/visual_studio/nevada_test_site/source/workspace/internship/hamiltonian/start.cu(163): error C2766: explicit specialization; 'SELECTOR_INT<MAX_VAL>::CHOOSED<>' has already been defined 

1>D:/Dev/visual_studio/nevada_test_site/source/workspace/internship/hamiltonian/start.cu(162): note: see previous definition of 'CHOOSED<, ?? :: ?? :: ?? ::<unnamed-enum-success_8> >' 

1>D:/Dev/visual_studio/nevada_test_site/source/workspace/internship/hamiltonian/start.cu(171): note: see reference to class template instantiation 'SELECTOR_INT<MAX_VAL>' being compiled 

1>D:/Dev/visual_studio/nevada_test_site/source/workspace/internship/hamiltonian/start.cu(164): error C2766: explicit specialization; 'SELECTOR_INT<MAX_VAL>::CHOOSED<>' has already been defined 

1>D:/Dev/visual_studio/nevada_test_site/source/workspace/internship/hamiltonian/start.cu(162): note: see previous definition of 'CHOOSED<, ?? :: ?? :: ?? ::<unnamed-enum-success_8> >' 

1>D:/Dev/visual_studio/nevada_test_site/source/workspace/internship/hamiltonian/start.cu(165): error C2766: explicit specialization; 'SELECTOR_INT<MAX_VAL>::CHOOSED<>' has already been defined 

1>D:/Dev/visual_studio/nevada_test_site/source/workspace/internship/hamiltonian/start.cu(162): note: see previous definition of 'CHOOSED<, ?? :: ?? :: ?? ::<unnamed-enum-success_8> >' 

1>D:/Dev/visual_studio/nevada_test_site/source/workspace/internship/hamiltonian/start.cu(169): error C2027: use of undefined type 'SELECTOR_INT<4>::CHOOSED<0>' 

1>D:/Dev/visual_studio/nevada_test_site/source/workspace/internship/hamiltonian/start.cu(169): note: see declaration of 'SELECTOR_INT<4>::CHOOSED<0>' 

1>D:/Dev/visual_studio/nevada_test_site/source/workspace/internship/hamiltonian/start.cu(187): note: see reference to class template instantiation 'SELECTOR_INT<4>' being compiled 

1>D:/Dev/visual_studio/nevada_test_site/source/workspace/internship/hamiltonian/start.cu(169): error C2061: syntax error: identifier 'TYPE' 

1>D:/Dev/visual_studio/nevada_test_site/source/workspace/internship/hamiltonian/start.cu(169): error C2238: unexpected token(s) preceding ';' 

1>D:/Dev/visual_studio/nevada_test_site/source/workspace/internship/hamiltonian/start.cu(187): error C2039: 'TYPE': is not a member of 'SELECTOR_INT<4>' 

1>D:/Dev/visual_studio/nevada_test_site/source/workspace/internship/hamiltonian/start.cu(187): note: see declaration of 'SELECTOR_INT<4>' 

1>D:/Dev/visual_studio/nevada_test_site/source/workspace/internship/hamiltonian/start.cu(187): error C2061: syntax error: identifier 'TYPE' 

Question:

Comment puis-je résoudre ce problème?

+0

'static enum'? – LogicStuff

+0

Je pensais que c'était le cas. Je crois (mais je ne suis pas sûr) que l'erreur signale que j'ai créé plusieurs instances de cette classe. Si je supprime la déclaration "template" de la classe 'SELECTOR_INT' tout fonctionne correctement. par exemple. 'erreur C2766: spécialisation explicite; 'SELECTOR_INT :: CHOOSED <>' a déjà été défini ' – cukier9a7b5

+0

Eh bien, un [mcve] aiderait, ou au moins dire quelle ligne est ce que dans votre question. Cela réglerait votre question. – Yakk

Répondre

3

Votre code présente de nombreux problèmes. Mauvais identifiants, essayant de spécialiser les classes internes, etc. Et peut-être que quelque chose ne va pas dans la logique. Quoi qu'il en soit, je n'aime pas l'approche; cela implique des nombres magiques et des macros et c'est un gâchis. Il suffit de résoudre le problème directement:

template<std::size_t I> 
struct index { 
    static constexpr std::size_t value=I; 
    constexpr operator std::size_t()const{return I;} 
    constexpr index(){} 
}; 

Cela simplifie simplement ce qui suit.

first_ prend une séquence de bools et vous dit que l'on est le premier vrai:

template<bool...> 
struct first_ {}; 
template<bool... bs> 
struct first_<true, bs...>:index<0>{}; 
template<bool... bs> 
struct first_<false, bs...>:index<first_<bs...>::value+1>{}; 

nth prend un index et une séquence de types, et renvoie le type n-ième:

template<std::size_t N, class...Ts> 
struct nth_impl{}; 
template<class T0, class...Ts> 
struct nth_impl<0, T0,Ts...>{using type=T0;}; 
template<std::size_t N, class T0, class...Ts> 
struct nth_impl<N, T0,Ts...>:nth_impl<N-1,Ts...>{}; 
template<std::size_t N, class...Ts> 
using nth=typename nth_impl<N,Ts...>::type; 

on résout le problème d'une manière générique:

template<class T, T x, class...Ts> 
using smallest_that_fits = nth< first_<(x<=std::numeric_limits<Ts>::max())...>::value, Ts... >; 

Enfin, nous résoudre votre sous-problème spécifique:

template<std::int64_t x> 
using choice = smallest_that_fits< 
    std::int64_t, x, 
    std::int8_t, std::int16_t, std::int32_t, std::int64_t 
>; 

Vous pouvez écrire à l'aide nthstd::tuple si vous préférez. Et index peut être un alias pour std::integral_constant<std::size_t.

first_ a un arrière _ comme sinon mon compilateur explose dans un bogue de compilateur.

+1

Merci. Je viens de commencer avec la métaprogrammation ... Et j'ai beaucoup à apprendre ... Le tutoriel que j'ai lu a résolu les problèmes comme je l'ai fait ci-dessus avec les types 'enum' mais' C++ 11' nous a apporté quelque chose de mieux - le 'constexpr' – cukier9a7b5