ATLAS Offline Software
safe_clid.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
3 */
4 /**
5  * @file AthenaeKernel/tools/safe_clid.icc
6  * @author scott snyder
7  * @date Nov 2005
8  * @brief Find the class ID of a type, without triggering an error
9  * if it isn't defined.
10  * Implementation file.
11  */
12 
13 #include "AthenaKernel/ClassID_traits.h"
14 #include <type_traits>
15 
16 
17 namespace SG {
18 
19 
20 //-------------------------------------------------------------------------
21 // Here's the first part. @a safe_clid has the job of calling one of the
22 // two @a safe_clid_1 overrides, depending on the state of the traits
23 // class @a has_classID_tag definition. We want the first one to be called
24 // when @a has_classID_tag is @a true_tag, and the second to be called
25 // in other cases (including the possibility that the typedef does not exist).
26 // There are three possibilities to consider.
27 //
28 // 1. The traits class defines @a has_classID_tag as @a true_tag.
29 // Here, both decl 1 and 2 match the call. It turns out
30 // that we can't use partial ordering to discriminate between
31 // these two on the basis of the tag (second) argument alone.
32 // That's the purpose of the first (dummy) argument. By making
33 // it a pointer in decl 1 and completely generic in decl 2,
34 // we ensure that decl 1 is a more specific match when both
35 // decls are allowed.
36 //
37 // 2. The traits class defines @a has_classID_tag as something
38 // other than @a true_tag. In this case, decl 1 doesn't match
39 // the call, but decl 2 will. So decl 2 will be called.
40 //
41 // 3. The traits class has no definition for @a has_classID_tag.
42 // In this case, the type named in decl 1 does not exist.
43 // However, that is @e not an error --- it just means that
44 // decl 1 won't be considered as a candidate overload.
45 // (Look up ``substitution failure is not an error'' (SFINAE).)
46 // So again, decl 2 gets called. Note that the requirement
47 // to handle this case (which comes about because the unspecialized
48 // version of @a ClassID_traits does not define this typedef)
49 // is why this may look backwards, using @a true_tag in the call,
50 // and the traits class typedef in the argument.
51 
52 
53 // Decl 1
54 template <class T>
55 constexpr CLID safe_clid_1 (T*, typename ClassID_traits<T>::has_classID_tag);
56 
57 // Decl 2
58 template <class T, class U>
59 constexpr CLID safe_clid_1 (T, U);
60 
61 // This is the public entry point.
62 template <class T>
63 constexpr CLID safe_clid()
64 {
65  return safe_clid_1 ((T*)0, std::true_type());
66 }
67 
68 
69 //-------------------------------------------------------------------------
70 // Here is the definition for decl 1. This gets called when the
71 // traits class defines @a has_classID_tag as @a true_tag.
72 // So we can go ahead and ask for the ID in this case.
73 
74 template <class T>
75 constexpr CLID safe_clid_1 (T*, typename ClassID_traits<T>::has_classID_tag)
76 {
77  return ClassID_traits<T>::ID();
78 }
79 
80 
81 //-------------------------------------------------------------------------
82 // Here is the definition for decl 2. This gets called when the traits
83 // class does not define @a has_classID_tag is @a true_tag.
84 // But there is one further decision to be made. If @a T derives
85 // from @a DataObject, then we can still get the class ID.
86 // Otherwise, we must return @a CLID_NULL.
87 
88 // This is called if @a T does not derive from @a DataObject.
89 // Return @a CLID_NULL.
90 template <class T, bool B>
91 struct safe_clid_2
92 {
93  constexpr static CLID clid() { return CLID_NULL; }
94 };
95 
96 // This specialization is used if @a T does derive from @a DataObject.
97 // This returns the class ID.
98 template <class T>
99 struct safe_clid_2<T, true>
100 {
101  constexpr static CLID clid() { return ClassID_traits<T>::ID(); }
102 };
103 
104 // This is the definition corresponding to decl 2 above.
105 // We test @a s_isDataObject in the traits class.
106 // Note that here @a T will be a pointer to the class we're
107 // actually interested in, so we need to strip a pointer.
108 template <class T, class U>
109 constexpr CLID safe_clid_1 (T, U)
110 {
111  using typ = std::remove_pointer_t<T>;
112  return safe_clid_2<typ, ClassID_traits<typ>::s_isDataObject>::clid();
113 }
114 
115 
116 } // namespace SG
117 
118