See blog post for more information.
Project is released under MIT licence.
cpp-traits-v2 | |
cpp-traits-v2.exe | |
#pragma once | |
template<typename Tree> struct OMTraits; | |
template<typename Tree> | |
class Algorithm | |
{ | |
public: | |
typedef typename OMTraits<Tree>::Node Node; | |
typedef typename OMTraits<Tree>::NodeType NodeType; | |
static const NodeType NodeType_TERMINAL = OMTraits<Tree>::NodeType_TERMINAL; | |
static const NodeType NodeType_NONTERMINAL = OMTraits<Tree>::NodeType_NONTERMINAL; | |
void dumpTree(const Tree &tree) const | |
{ | |
cout << "Tree: " << tree.name() << endl; | |
for (typename vector<Node>::const_iterator i = tree.nodes().begin(); i != tree.nodes().end(); ++i) | |
{ | |
dumpNode(*i); | |
} | |
} | |
private: | |
void dumpNode(const Node &node) const | |
{ | |
cout << " " << node.name() << ": " << getNodeTypeString(node.type()) << endl; | |
} | |
string getNodeTypeString(NodeType nodeType) const | |
{ | |
switch (nodeType) | |
{ | |
case NodeType_TERMINAL: return "TERMINAL"; | |
case NodeType_NONTERMINAL: return "NONTERMINAL"; | |
default: return "(other)"; | |
} | |
} | |
}; | |
#pragma once | |
#include <string> | |
#include <iostream> | |
#include <vector> | |
using namespace std; | |
The MIT License (MIT) | |
Copyright (c) 2014 Richard Cook | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
SOFTWARE. |
#include "common.hpp" | |
#include "om1.hpp" | |
#include "om2.hpp" | |
#include "algorithm.hpp" | |
template<> | |
struct OMTraits<OM1::Tree> | |
{ | |
typedef OM1::Node Node; | |
typedef OM1::NodeType NodeType; | |
// BEGIN: Generated static constants for enums | |
static const OM1::NodeType NodeType_TERMINAL = OM1::TERMINAL; | |
static const OM1::NodeType NodeType_NONTERMINAL = OM1::NONTERMINAL; | |
// END: Generated static constants for enums | |
}; | |
template<> | |
struct OMTraits<OM2::Tree> | |
{ | |
typedef OM2::Node Node; | |
typedef OM2::NodeType NodeType; | |
// BEGIN: Generated static constants for enums | |
static const OM2::NodeType NodeType_TERMINAL = OM2::TERMINAL; | |
static const OM2::NodeType NodeType_NONTERMINAL = OM2::NONTERMINAL; | |
// END: Generated static constants for enums | |
}; | |
// Partial method specialization for type-specific behaviours | |
template<> | |
void Algorithm<OM2::Tree>::dumpNode(const Node &node) const | |
{ | |
cout << " [specialized behaviour] " << node.name() << ": " << getNodeTypeString(node.type()) << endl; | |
} | |
int main() | |
{ | |
OM1::Tree tree1("OM1::Tree"); | |
tree1.addNode(OM1::Node("OM1::Node1", OM1::TERMINAL)); | |
tree1.addNode(OM1::Node("OM1::Node2", OM1::NONTERMINAL)); | |
Algorithm<OM1::Tree> algorithm1; | |
algorithm1.dumpTree(tree1); | |
OM2::Tree tree2("OM2::Tree"); | |
tree2.addNode(OM2::Node("OM2::Node1", OM2::TERMINAL)); | |
tree2.addNode(OM2::Node("OM2::Node2", OM2::NONTERMINAL)); | |
Algorithm<OM2::Tree> algorithm2; | |
algorithm2.dumpTree(tree2); | |
return 0; | |
} | |
CPP := g++ | |
TARGET := cpp-traits-v2 | |
all: $(TARGET) | |
$(TARGET): main.cpp *.hpp | |
$(CPP) -o $@ main.cpp | |
.PHONY: clean | |
clean: | |
rm -f $(TARGET) | |
#pragma once | |
namespace OM1 | |
{ | |
// Same enum member names as ObjectModel2::NodeType but different values | |
enum NodeType { TERMINAL = 100, NONTERMINAL = 101 }; | |
class Node | |
{ | |
public: | |
Node(const string &name, NodeType type) : m_name(name), m_type(type) { } | |
const string &name() const { return m_name; } | |
NodeType type() const { return m_type; } | |
private: | |
string m_name; | |
NodeType m_type; | |
}; | |
class Tree | |
{ | |
public: | |
Tree(const string &name) : m_name(name) { } | |
const string &name() const { return m_name; } | |
const vector<Node> &nodes() const { return m_nodes; } | |
void addNode(const Node &node) { m_nodes.push_back(node); } | |
private: | |
string m_name; | |
vector<Node> m_nodes; | |
}; | |
} | |
#pragma once | |
namespace OM2 | |
{ | |
// Same enum member names as ObjectModel1::NodeType but different values | |
enum NodeType { TERMINAL = 200, NONTERMINAL = 201 }; | |
class Node | |
{ | |
public: | |
Node(const string &name, NodeType type) : m_name(name), m_type(type) { } | |
const string &name() const { return m_name; } | |
NodeType type() const { return m_type; } | |
private: | |
string m_name; | |
NodeType m_type; | |
}; | |
class Tree | |
{ | |
public: | |
Tree(const string &name) : m_name(name) { } | |
const string &name() const { return m_name; } | |
const vector<Node> &nodes() const { return m_nodes; } | |
void addNode(const Node &node) { m_nodes.push_back(node); } | |
private: | |
string m_name; | |
vector<Node> m_nodes; | |
}; | |
} | |