método de fábrica retornando uma instanciação concreta de uma classe C ++ modelo

StackOverflow https://stackoverflow.com/questions/498757

  •  20-08-2019
  •  | 
  •  

Pergunta

Eu tenho uma classe

template <unsigned int N>
class StaticVector {
// stuff
};

Como posso declarar e definir nesta classe um método de fábrica estático retornando um StaticVector <3> objeto, sth como

StaticVector<3> create3dVec(double x1, double x2, double x2);

?

Foi útil?

Solução

"Como posso declarar e definir nesta classe"

Em que classe? Você definiu um modelo de classe, não uma classe. Você não pode chamar uma função estática de si um modelo de classe, você tem que chamar uma versão específica da função estática que da parte de uma classe real.

Então, você quer o modelo (e, logo, todos instantiations dele) para ter uma função retornando um StaticVector <3>, ou você quer uma instanciação particular desse modelo para ter uma função retornando um StaticVector <3>?

Se o ex-:


  template <unsigned int N>
  struct SV {
    int contents[N];
    static SV<3> get3dVec(int x, int y, int z) {
      SV<3> v;
      v.contents[0] = x;
      v.contents[1] = y;
      v.contents[2] = z;
      return v;
    }
  };

  int main() {
    SV<3> v = SV<1>::get3dVec(1,2,3);
  }

funciona para mim.

Se o último (só deseja get3dVec ser um membro de SV <3>, e não de todos SV ), então você quer especialização de modelo:


  template <unsigned int N>
  struct SV {
    int contents[N];
  };

  template<>
  struct SV<3> {
    int contents[3]; // must be re-declared in the specialization
    static SV<3> get3dVec(int x, int y, int z) {
      SV<3> v;
      v.contents[0] = x;
      v.contents[1] = y;
      v.contents[2] = z;
      return v;
    }
  };

  int main() {
    SV<3> v = SV<1>::get3dVec(1,2,3); // compile error
    SV<3> v = SV<3>::get3dVec(1,2,3); // OK
  }

Se por nenhuma outra razão do que para fazer a chamar mais agradável código visual omitindo o parâmetro do modelo basicamente irrelevantes, eu concordo com Iraimbilanja que normalmente uma função livre (em um namespace Se você estiver escrevendo para reutilização) faria mais sentir para este exemplo.

C ++ modelos significa que você não precisa de funções estáticas tanto em C ++ como você fazer em Java: se você quiser uma função "foo" que faz uma coisa para a classe Bar e outra coisa para a classe Baz, você pode declará-lo como um modelo de função com um parâmetro de modelo que pode ser Bar ou Baz (e que pode ou não pode ser inferida a partir de parâmetros da função), ao invés de torná-lo uma função estática em cada classe. Mas se você quer que ele seja uma função estática, então você tem que chamá-lo usando uma classe específica, não apenas um nome de modelo.

Outras dicas

Algo como:

template< unsigned int SIZE >
StaticVector< SIZE > createVec( const std::tr1::array< double, SIZE >& values )
{ 
     StaticVector< SIZE > vector;
     for( int i = 0; i < values.size(); ++i ) // here assuming that StaticVector have [] operator to access values on write
     {
         vector[i] = values[i];
     }

     return vector;
}

... ou uma variante certamente trabalho. (Teste fez'nt-lo)

Uso seria:

std::tr1::array< double, 3 > vectorValues = { 10.0, 10.0, 42.0 };

StaticVector<3> vector1 = createVector( vectorValues ); // if the compiler can guess the size from the array information
StaticVector<3> vector2 = createVector<3>( vectorValues ); // if you have to specify the size

Uma alternativa seria substituir std :: tr1 :: série por um conjunto básico, mas estaria usando matrizes matérias em seus próprios riscos:)

Em primeiro lugar, eu acredito que você originalmente médio de retorno

StaticVector<N>

Em vez de sempre uma especialização com N == 3. Então, o que você quer fazer é escrevê-lo como este:

template <unsigned int N>
class StaticVector {
public:
    // because of the injected class-name, we can refer to us using
    // StaticVector . That is, we don't need to name all template
    // parameters like StaticVector<N>.
    static StaticVector create3dVec(double x1, double x2, double x2) {
        // create a new, empty, StaticVector
        return StaticVector();
    }

};

Se você realmente quer voltar sempre uma 3dVector, você provavelmente quer limitar a N == 3, de modo que, por exemplo StaticVector<4>::create3dVec não funciona. Você pode fazer isso usando a técnica descrita aqui .

Se você quer ter uma função como createVec que funciona com qualquer tamanho, você provavelmente vai querer substituir os parâmetros com uma matriz. Você pode fazer o contrário, mas isso é avançado e requer alguns truques macro aplicadas com boost :: pré-processador. Não vale a pena eu acho. A próxima versão C ++ irá fornecer variádica modelos para esta finalidade. De qualquer forma, considere usar algo como isto:

Eu acho que só complicaria este desnecessariamente aqui. Uma solução rápida é usar um boost :: fusion :: vector em vez disso, colocá-lo no modelo de classe em vez da versão anterior:

static StaticVector createVec(double (&values)[N]) {
    // create a new, empty, StaticVector, initializing it
    // with the given array of N values.
    return StaticVector();
}

Você poderia usá-lo com

double values[3] = {1, 2, 3};
StaticVector<3> v = StaticVector<3>::createVec(values);

Note que aceita uma matriz por referência. Você não pode dar-lhe um ponteiro. Isso é porque ele corresponde a utilização de parâmetros: Você não poderia fornecer menos ou mais argumentos para o outro lado também. Ele também irá protegê-lo de casos como este:

// oops, values is a null pointer!
StaticVector<3> v = StaticVector<3>::createVec(values);

Uma matriz nunca pode ser um ponteiro nulo. Claro, se você gosta, você sempre pode mudar o parâmetro de matriz para um ponteiro. Seria apenas a minha preferência pessoal:)

@ litb

Eu queria voltar um vetor 3-elemento. A razão é que estes vetores são supostamente entidades geométricas, por isso não há necessidade de N para ser muito alto (eu não sou um físico corda, então eu não fazer o trabalho em espaços de 11 dimensões). Eu queria criar um modelo para evitar a duplicação de código, mas mantê-1, 2 e vetores 3-dimensionais como tipos separados.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top