|         |      1 #include <iostream> | 
|         |      2 #include <boost/utility.hpp> | 
|         |      3  | 
|         |      4 using namespace std; | 
|         |      5 using namespace boost; | 
|         |      6  | 
|         |      7 struct True { | 
|         |      8   static const bool value = true; | 
|         |      9 }; | 
|         |     10 struct False { | 
|         |     11   static const bool value = false; | 
|         |     12 }; | 
|         |     13  | 
|         |     14 // Here are some graph structures. Some of them define the type "OneTag" | 
|         |     15 // to True or False, some does not. Not defining a tag is (or at least | 
|         |     16 // should be) equivalent to defining it to "False". | 
|         |     17 struct Graph1 {}; | 
|         |     18 struct Graph2 { | 
|         |     19   typedef True OneTag; | 
|         |     20 }; | 
|         |     21 struct Graph3 { | 
|         |     22   typedef False OneTag; | 
|         |     23 }; | 
|         |     24  | 
|         |     25  | 
|         |     26 /**************** The first method to use tags ****************/ | 
|         |     27  | 
|         |     28 template <typename Graph, typename Enable = void> | 
|         |     29 struct HasOneTag { | 
|         |     30   typedef False TheTag; | 
|         |     31 }; | 
|         |     32  | 
|         |     33 // specialization for those graphs which defined the tag to be true: | 
|         |     34 template <typename Graph> | 
|         |     35 struct HasOneTag<Graph, typename enable_if<typename Graph::OneTag>::type > { | 
|         |     36   typedef True TheTag; | 
|         |     37 }; | 
|         |     38  | 
|         |     39 template <typename Graph> | 
|         |     40 int cn1(const Graph &, False) { | 
|         |     41   return 0; | 
|         |     42 } | 
|         |     43  | 
|         |     44 template <typename Graph> | 
|         |     45 int cn1(const Graph &, True) { | 
|         |     46   return 1; | 
|         |     47 } | 
|         |     48  | 
|         |     49 template <typename Graph> | 
|         |     50 int cn1(const Graph &g) { | 
|         |     51   return cn1(g, typename HasOneTag<Graph>::TheTag()); | 
|         |     52 } | 
|         |     53  | 
|         |     54 /**************** The second method ****************/ | 
|         |     55  | 
|         |     56 // An artificial type to provoke a conversion to avoid ambuguity... | 
|         |     57 template <typename T> | 
|         |     58 struct Wrap { | 
|         |     59   const T &value; | 
|         |     60   Wrap(const T &t) : value(t) {} | 
|         |     61 }; | 
|         |     62  | 
|         |     63 template <typename Graph> | 
|         |     64 typename enable_if<typename Graph::OneTag, int>::type | 
|         |     65 _cn2(const Graph &) { | 
|         |     66   return 1; | 
|         |     67 } | 
|         |     68  | 
|         |     69 template <typename Graph> | 
|         |     70 int _cn2(Wrap<Graph>) { | 
|         |     71   return 0; | 
|         |     72 } | 
|         |     73  | 
|         |     74 template <typename Graph> | 
|         |     75 int cn2(const Graph& g) { | 
|         |     76   return _cn2<Graph>(g); | 
|         |     77 } | 
|         |     78  | 
|         |     79  | 
|         |     80 int main() { | 
|         |     81   Graph1 g1; | 
|         |     82   Graph2 g2; | 
|         |     83   Graph3 g3; | 
|         |     84  | 
|         |     85   cout << "The first method:\n"; | 
|         |     86   cout << "G1: " << cn1(g1) << endl; | 
|         |     87   cout << "G2: " << cn1(g2) << endl; | 
|         |     88   cout << "G3: " << cn1(g3) << endl; | 
|         |     89  | 
|         |     90   cout << "The second method:\n"; | 
|         |     91   cout << "G1: " << cn2(g1) << endl; | 
|         |     92   cout << "G2: " << cn2(g2) << endl; | 
|         |     93   cout << "G3: " << cn2(g3) << endl; | 
|         |     94  | 
|         |     95 } |