Question

Pour l'essentiel, la situation se présente comme suit:

J'ai un modèle de classe (en utilisant un paramètre modèle length de type int) et que vous souhaitez introduire un tableau statique. Ce tableau devrait être de length de longueur et contiennent les éléments 1 à length.

Les regards de code comme suit jusqu'à présent:

template<int length>
class myClass{
    static int array[length];
};

Alors je voulais écrire une ligne pour initalizing le tableau

// of course, the line below does not work as intended.
template<int length> int myClass<length>::array[length]={1,2, ..., length};

(Comment) peut-il être atteint?

Était-ce utile?

La solution

Utilisez expression "constructeur statique".

// EDIT 2

#include <iostream>

template<int length>
class myClass {
public:
    typedef int ArrayType[length];

    static struct StaticData {
        ArrayType array;

        StaticData()
        {
            for (int i = 0; i < length; i++) array[i] = i;
        }
    }
    static_data;

    static ArrayType &array;
};

template<int length>
typename myClass<length>::StaticData myClass<length>::static_data;

template<int length>
typename myClass<length>::ArrayType &myClass<length>::array = myClass<length>::static_data.array;

int main(int argc, char** argv) {
    const int LEN = 5;
    for (int i = 0; i < LEN; i++) {
        std::cout << myClass<LEN>::array[i];
    }
}

Autres conseils

Vous ne pouvez pas le faire avec des tableaux de style C car ils n'ont pas la sémantique de valeur.

Si vous utilisez quelque chose comme std::tr1::array mais vous pouvez facilement faire ce que vous voulez en initialisant à un résultat de fonction, ou en utilisant un itérateur qui génère ces valeurs.

Vous pouvez écrire une classe wrapper, mais je suis sûr qu'il ya des solutions plus propres:

template <size_t length>
class array_init_1_to_n
{
    int array[length];

public:

    array_init_1_to_n()
    {
        for (int i = 0; i < length; ++i)
        {
            array[i] = i + 1;
        }
    }

    operator int*()
    {
        return array;
    }

    operator const int*() const
    {
        return array;
    }
};

template<size_t length>
class myClass{
    static array_init_1_to_n<length> array;
};

Il semble difficile. L'approche la plus proche que je peux penser serait le suivant:

template<int length>
class myClass
{
  public:
    myClass()
    {
      static InitializeArray<length> initializeArray(&array);
    }
    template<int length>
    class InitializeArray
    {
    public:
      InitializeArray(int* array) 
      {
        for(int i = 0; i < length ; ++i)
        array[i] = i;
      }
    };
    static int array[length];
    static myClass instance;
};
template<int length> int myClass<length>::array[length];
template<int length> myClass myClass::instance;

ne peut pas vous envelopper le tableau dans une fonction statique, par exemple,

template<int length>
class myClass {
    static int* myArray() {
        static bool initd = false;
        static int array[length];
        if(!initd) {
            for(int i=0; i<length; ++i) {
                array[i] = i+1;
            }
            initd = true;
        }
        return array;
    };
};

et accéder ensuite comme,

myClass<4>::myArray()[2] = 42;

Il sera initialisés sur la première utilisation, et suivant les accès depuis initd est statique, if(!initd) sera faux et l'étape d'initialisation est sautée.

Je pense que cela ne fonctionne que dans C ++ 0x. En C ++ 03 quoi que vous fassiez - vous finirez avec un tableau initialisé dynamiquement, et donc potentiellement des problèmes d'ordre d'initialisation. Le code suivant C ++ 0x aura pas de tels problèmes.

template<int...>
struct myArray;

template<int N, int ...Ns>
struct myArray<N, Ns...> : myArray<N-1, N, Ns...> { };

template<int ...Ns>
struct myArray<0, Ns...> {
    static int array[sizeof...(Ns)];
};

template<int ...Ns>
int myArray<0, Ns...>::array[sizeof...(Ns)] = { Ns... } ;

template<int length>
class myClass : myArray<length> {
    using myArray<length>::array;
};

intégrer une boucle dans un constructeur statique qui court jusqu'à la longueur, son fondamentalement la même que l'utilisation du initialiseur:

for(int i = 0; i < length; i++)
    array[i] = i + 1;

Voici un exemple en utilisant Boost.MPL:

#include <cstddef>
#include <iostream>

#include <boost/mpl/range_c.hpp>
#include <boost/mpl/string.hpp>

template<std::size_t length>
struct myClass {
  static const std::size_t Length = length;
  typedef typename boost::mpl::c_str< boost::mpl::range_c<std::size_t, 1, length + 1> > Array;
};

int main() {
  // check whether the array really contains the indented values
  typedef myClass<10> test;
  for (std::size_t i = 0; i < test::Length; ++i) {
    std::cout << test::Array::value[i] << std::endl;
  }
}

Notez que le tableau est plus grand que length; actuellement sa taille est fixe.

Vous pouvez utiliser instanciation explicite de modèle d'un membre statique supplémentaire dont le constructeur prend soin de remplir les entrées:

template<int length>
class myClass{
public:
    static int array[length];

    typedef enum{LENGTH=length} size_;

    struct filler
    {
        filler(void)
        {
            for(int i=0;i<LENGTH;++i)
                array[i]=i+1;
        }
    };

    static filler fill_;
};

// of course, the line[s] below now do work as intended.
template<int length> 
int myClass<length>::array[length];

//static member definition
template<int length>
typename myClass<length>::filler myClass<length>::fill_;

//explicit template instantiation
template myClass<5>::filler myClass<5>::fill_;

int main(void)
{
    for(int i=0;i<myClass<5>::LENGTH;++i)
        cout<<myClass<5>::array[i]<<endl;

    return 0;
}

Ou, comme une solution similaire (probablement mieux) a déjà été indiqué ci-dessus par Benoit, voici une version récursive de modèle, juste pour le plaisir:

//recursive version:
template<int length>
class myClass{
public:
    static int array[length];

    typedef enum{LENGTH=length} size_;

    static void do_fill(int* the_array)
    {
        the_array[LENGTH-1]=LENGTH;
        myClass<length-1>::do_fill(the_array);
    }

    struct filler
    {
        filler(void)
        {
            /*for(int i=0;i<LENGTH;++i)
                array[i]=i+1;*/
            do_fill(array);
        }
    };

    static filler fill_;
};

//explicit specialization to end the recursion
template<>
class myClass<1>{
public:
    static int array[1];

    typedef enum{LENGTH=1} size_;

    static void do_fill(int* the_array)
    {
        the_array[LENGTH-1]=LENGTH;
    }
};

//definition of the explicitly specialized version of the array
//to make the linker happy:
int myClass<1>::array[1];

// of course, the line below does not work as intended.
template<int length> 
int myClass<length>::array[length];

//static member definition
template<int length>
typename myClass<length>::filler myClass<length>::fill_;

//explicit template instantiation
template myClass<5>::filler myClass<5>::fill_;

int main(void)
{
    for(int i=0;i<myClass<5>::LENGTH;++i)
        cout<<myClass<5>::array[i]<<endl;

    return 0;
}

Maintenant, différents compilateurs prennent en charge différents niveaux de récursivité modèle (et cette technique est compilateur cher) donc, attention ... "Here Be Dragons"; -)

Oh, encore une chose, vous n'avez pas besoin de redéfinir le tableau dans la version spécialisée de myClass, de sorte que vous pouvez vous débarrasser de tableau instanciation [1]:

//explicit specialization to end the recursion
template<>
class myClass<1>{
public:
    typedef enum{LENGTH=1} size_;

    static void do_fill(int* the_array)
    {
        the_array[LENGTH-1]=LENGTH;
    }
};
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top