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; | |
| }; | |
| } | |