ATLAS Offline Software
Loading...
Searching...
No Matches
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
17namespace 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
54template <class T>
55constexpr CLID safe_clid_1 (T*, typename ClassID_traits<T>::has_classID_tag);
56
57// Decl 2
58template <class T, class U>
59constexpr CLID safe_clid_1 (T, U);
60
61// This is the public entry point.
62template <class T>
63constexpr 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
74template <class T>
75constexpr 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.
90template <class T, bool B>
91struct 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.
98template <class T>
99struct 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.
108template <class T, class U>
109constexpr 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