Domanda

Ho una funzione per calcolare gradiente di diversa variabile definita sul set di punti vicini. L'algoritmo è sempre lo stesso, ma a seconda di ciò che è calcolata, si accede diversi dati utente dei vicini, ad esempio quando si calcolano gradiente di velocità , l'uso Node::velocity, nel calcolo gradiente di stress , l'uso Node::stress. Qual è il modo migliore per evitare di scrivere la stessa funzione più volte?

Ho avuto diverse possibilità in mente:

  1. funzione lambda Pass (c ++ 0x) o un oggetto richiamabile restituire quella particolare i dati dei membri in questione, chiamato come

    gradVelocity=computeGradient(listOfNeighbors,[](const Node& n){ return n.velocity; });
    

    L'unico neo è chiamata di funzione in più ad ogni lettura.

  2. Modello la funzione in base a numero intero dicendo ciò che viene calcolato:

    enum{VAL_VELOCITY=0,VAL_STRESS,VAL_SOMETHING};
    template<int what> computeGradient(const std::list<Node>& neighbors){
        /*loop over neighbors*/
             value=(what==VAL_VELOCITY?neighbor.velocity:((what==VAL_STRESS)?neighbor.stress:neighbor.something);
        /* and so on */
    }
    
    /* called like this */
    gradVelocity=computeGradient<VAL_VELOCITY>(neighbors);
    

    Dovrebbe essere forse efficiente (compilatore sperando ottimizzare il condizionale con costanti via in singole istanze), ma la leggibilità e la manutenibilità è piuttosto bassa.

Alcuni un'idea migliore?

È stato utile?

Soluzione

Puntatore membro è quello che serve. Il tipo è scritto come T S::* T è il tipo di membro di dati, S è la vostra struct o classe. Ecco un piccolo esempio:

#include <iostream>

struct Foo
{
  int a;
  double b;

  Foo(int a, double b)
    : a(a), b(b)
  { }
};

template<typename T, T Foo::* mem>
void print(const Foo& foo)
{
  std::cout << foo.*mem << std::endl;
}

int main()
{
  Foo f(5, 3.14);
  print<int, &Foo::a>(f);
  print<double, &Foo::b>(f);
}

Altri suggerimenti

Se tutti i campi hanno lo stesso tipo, è facile da usare puntatori a membri:

struct Node
{
  double stress;
  double velosity;
};

void foo(Node* pNode, double Node::*pValue)
{
  cout << pNode->*pValue << endl;
}

int main()
{
  Node n1 = { 1, 2 };

  foo(&n1, &Node::stress);
  foo(&n1, &Node::velosity);
}

Aggiornamento: In caso contrario, è ancora facile da combinare i puntatori ai membri con i modelli:

struct Node
{
  double stress;
  double velosity;
  int dimension;
};

template<class T>
void foo(Node* pNode, T Node::*pValue)
{
  cout << pNode->*pValue << endl;
}

int main()
{
  Node n1 = { 1, 2 };

  foo(&n1, &Node::stress);
  foo(&n1, &Node::velosity);
  foo(&n1, &Node::dimension);
}

Credo che questo è probabilmente il modo più efficiente possibile. E 'abbastanza chiaro anche.

Sono un grande fan di Boost.Fusion, e più specificamente, il Boost.Fusion.Map , che consentono di costruire un tipo -.> valore sorta di mappa

struct Velocity {};
struct Stress {};

typedef boost::fusion::map<
  std::pair<Velocity, double>,
  std::pair<Stress, int>
> Map;

Map map;

Ora, è possibile accedere alla mappa con i tipi:

boost::fusion::at_key<Velocity>(map)

restituisce un riferimento a una variabile di tipo boost::fusion::result_of::at_key<Velocity, Map>::type

Con adeguato involucro, si ottiene:

extern Velocity const velocity;
extern Stress const stress;

myItem.access(stress) = 3;

E, naturalmente, visto che stiamo parlando di modelli, nessuna penalità runtime, a tutti:)

Che dire eredita da Node e l'utilizzo di accesso virtuale? Sarebbe anche possibile utilizzare CRTP per evitare la chiamata virtuale.

È possibile combinare velocity, stress, something in un singolo array e l'accesso loro sulla base dell'indice enum.

struct Node
{
  int attributes[3]; // contains 'velocity', 'stress', 'something';
  enum { VAL_VELOCITY=0, VAL_STRESS, VAL_SOMETHING };
};

Utilizzo:

Node n;
n.attributes[Node::VAL_VELOCITY] = <value>;  // writing 'Node::velocity'
<otherthing> = n.attributes[Node::VAL_SOMETHING]; // reading 'Node::something'

[Nota:. Se si desidera mantenere attributes all'interno regione private quindi fornire metodi getter e setter in Node per loro l'accesso a]

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top