Working with enumerated data in C ++

I am updating an old piece of C ++ code and focusing on a design problem and need advice on the best course of action. The code processes geometric data. Currently, the code defines many global constants for handling element types:

#define TETRAHEDRON 0
#define HEXAHEDRON 1

Each constant has information associated with it, which remains constant and which is currently processed by the class, in our case, Topology.

int Topology::nodesPerElement(int topType)
{    
    switch(topType) {
        case TETRAHEDRON:
            return 4;
            break;
        case HEXAHEDRON:
            return 8;
            break;
    }
}

, . , switch, . , . , .

- , .

, , .

" ", :

class Tetrahedron : public TopType {
    static const int nodesPerElement = 4;
    static const std::string name = "Tet";
    etc...
}

:

int Topology::nodesPerElement(TopType topType)
{
    return topType.nodesPerElement;
}

++? , , , , , . , .

+3
10

, , , , . , : , .

class TopologyObject
{
    private:
        int numberVertices;
        int numberFaces;
        // etc.

    public:
        int getVertices() { return numberVertices; };
        int getFaces() { return numberFaces; };

    protected:
        TopologyObject(int vertices, int faces) :
            numberVertices(vertices),
            numberFaces(faces)
        {};

    public:
        static TopologyObject Tetrahedron = new TopologyObject(4, 4);
        // etc.
}

Tetrahedron TopologyObject::Tetrahedron.

, , , .

+8

(, ), , . , nodesPerElement , .

, , . std::map, . .

, :

#include <cassert>
#include <iostream>
#include <map>
#include <string>

struct Topology
{
    enum Code {tetrahedron, hexahedron};
    int nodesPerElement;
    std::string name;
};

namespace // Anonymous namespace
{
    // Lookup table associating topology code with properties
    const struct {Topology::Code code; Topology topo;} topoTable_[] =
    {
        {Topology::tetrahedron,  {4, "Tetrahedron"}},
        {Topology::hexahedron,   {6, "Hexahedron"}}
    };
};

class TopologyMap // Singleton
{
public:
    static TopologyMap lookup(Topology::Code code)
    {
        return Topology(instance().doLookup(code));
    }

private:
    typedef std::map<Topology::Code, Topology> Map;
    Map map_;

    TopologyMap()
    {
        // Initialize map with constant property table
        size_t tableSize = sizeof(topoTable_) / sizeof(topoTable_[0]);
        for (size_t row=0; row<tableSize; ++row)
        {
            map_[topoTable_[row].code] = topoTable_[row].topo;
        }
    }

    static TopologyMap& instance()
    {
        static TopologyMap instance;
        return instance;
    }

    const Topology& doLookup(Topology::Code code) const
    {
        Map::const_iterator match = map_.find(code);
        assert(match != map_.end());
        return match->second;
    }
};

class Shape
{
public:
    Shape(Topology::Code topoCode)
    : topo_(TopologyMap::lookup(topoCode)) {}

    const Topology& topology() const {return topo_;}
    // etc...

private:
    Topology topo_;
};

int main()
{
    Shape shape1(Topology::tetrahedron);
    Shape shape2(Topology::hexahedron);
    std::cout << "shape1 is a " << shape1.topology().name << " with " <<
        shape1.topology().nodesPerElement << " nodes per element.\n";
    std::cout << "shape2 is a " << shape2.topology().name << " with " <<
        shape2.topology().nodesPerElement << " nodes per element.\n";
};

:

shape1 is a Tetrahedron with 4 nodes per element.
shape2 is a Hexahedron with 6 nodes per element.

, . , , - . , :

#include <cassert>
#include <iostream>
#include <map>
#include <string>

struct Topology
{
    enum Code {tetrahedron, hexahedron, CODE_COUNT};
    int nodesPerElement;
    std::string name;
};

namespace // Anonymous namespace
{
    // Lookup table associating topology code with properties
    const Topology topoTable_[] =
    {
        {4, "Tetrahedron"},
        {6, "Hexahedron"}
    };
};

class TopologyMap // Singleton
{
public:
    static Topology lookup(Topology::Code code)
    {
        assert(code < Topology::CODE_COUNT);
        return topoTable_[code];
    }

private:
    TopologyMap() {} // Non-instantiable
};

class Shape
{
public:
    Shape(Topology::Code topoCode)
    : topo_(TopologyMap::lookup(topoCode)) {}

    const Topology& topology() const {return topo_;}
    // etc...

private:
    Topology topo_;
};

int main()
{
    Shape shape1(Topology::tetrahedron);
    Shape shape2(Topology::hexahedron);
    std::cout << "shape1 is a " << shape1.topology().name << " with " <<
        shape1.topology().nodesPerElement << " nodes per element.\n";
    std::cout << "shape2 is a " << shape2.topology().name << " with " <<
        shape2.topology().nodesPerElement << " nodes per element.\n";
};

, Topology TopologyMap, Shape main.

+3

, Toplogy. , .

.

+2

, -. .

, traits , .

+2

, - Shape. / .

+1

, , - ?

, poop .

+1

topType 0, , . , , ,

  • : Easy
  • : Easy
  • : , .

TopologyType (.. ..), + , IMO.

+1

(-) , :

enum { tetrahedron, hexahedron };

template <int type>
struct nodes_per_element { int operator()() const { 
    throw std::invalid_argument("Attempt to use unknown shape");
};

template <>
struct nodes_per_element<tetrahedron> { int operator()() const { return 4; } };

template <>
struct nodes_per_element<hexahedron> { int operator()() const { return 8; } };

: int x = nodes_per_element<hexahedron>()(); , , , , () . , ( ).

, - , .

, , , , , , . , , :

struct shape_data { 
    int nodes_per_element;
    std::string name;
};

shape_data data[] = { 
    {4, "Tetrahedron"}, 
    {8, "Hexahedron" }
};

:

shape_data &s = data[hexahedron];

std::cout << "A " << s.name << " has " << s.nodes_per_element << "nodes per element.\n";
+1

, .

, :

  • (, )

, :

class Solid
{
  typedef std::vector<Solid> solids_type;
public:
  Solid(std::string name, size_t faces, size_t nodes):
    mName(name), mFaces(faces), mNodes(nodes)
  {
  }

  ///
  /// Properties
  ///
  const std::string& getName() const { return mName; }
  size_t getFaces() const { return mFaces; }
  size_t getNodes() const { return mNodes; }

  ///
  /// Collection Handling
  ///
  static bool Add(Solid solid); // only add if it not already there.

  ///
  /// struct Predicate: std::unary_function<Solid,bool>
  ///
  template <class Predicate>
  static const Solid* Get(Predicate pred)
  {
    solids_type::const_iterator it =
        std::find_if(Solids().begin(), Solids().end(), pred);
    return it == Solids().end()) ? 0 : &(*it);
  } // Get

  ///
  /// Some Predicates
  ///
  class ByName: std::unary_function<Solid,bool>
  {
  public:
    ByName(std::string name): mName(name) {}
    bool operator()(const Solid& s) const { return s.getName() == mName; }
  private:
    std::string mName;
  };

  class ByFaces; /// ...
  class ByNodes; /// ...

private:
  /// Properties
  std::string mName;
  size_t mFaces;
  size_t mNodes;

  /// Collection
  static solids_type& Solids()
  { 
    static solids_type MSolids;
    return MSolids;
  }
}; // class Solid

, :

// in tetrahedron.cpp
namespace
{
  bool gTetrahedron = Solid::Add(Solid("Tetrahedron", 4, 4));
}

// in main.cpp
int main(int argc, char* argv[])
{
  const Solid* myTetra = Solid::Get(Solid::ByFaces(4));

  assert(myTetra->getName() == "Tetrahedron");
  assert(myTetra->getFaces() == 4);
  assert(myTetra->getNodes() == 4);

  return 0;
} // main

:

:

+1

, . :

class Topology 
{
  public:

  virtual int nodesPerElement() const = 0;
  // etc
};

class Tetrahedrom : public Topology
{
   public:
   virtual nodesPerElement() const { return 4; }
   // etc
}

// etc

( ), ( ):

class Topology 
{
  public:

  virtual int nodesPerElement() const = 0;
  // etc
};

template<typename T>
class ConcreteTopology : public Topology
{
  public:

  virtual int nodesPerElement() const { return T::nodesPerElement; }
  // etc
};

struct Tetrahedron_Data {
  int nodesPerElement = 4; 
  // etc
};

typedef ConcreteTypology<Tetraheadron_Data> Tetrahedron;

// etc
0

Source: https://habr.com/ru/post/1731623/


All Articles