2 Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
5 * @file AthenaeKernel/tools/safe_clid.icc
8 * @brief Find the class ID of a type, without triggering an error
10 * Implementation file.
13#include "AthenaKernel/ClassID_traits.h"
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.
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
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.
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.
55constexpr CLID safe_clid_1 (T*, typename ClassID_traits<T>::has_classID_tag);
58template <class T, class U>
59constexpr CLID safe_clid_1 (T, U);
61// This is the public entry point.
63constexpr CLID safe_clid()
65 return safe_clid_1 ((T*)0, std::true_type());
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.
75constexpr CLID safe_clid_1 (T*, typename ClassID_traits<T>::has_classID_tag)
77 return ClassID_traits<T>::ID();
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.
88// This is called if @a T does not derive from @a DataObject.
89// Return @a CLID_NULL.
90template <class T, bool B>
93 constexpr static CLID clid() { return CLID_NULL; }
96// This specialization is used if @a T does derive from @a DataObject.
97// This returns the class ID.
99struct safe_clid_2<T, true>
101 constexpr static CLID clid() { return ClassID_traits<T>::ID(); }
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)
111 using typ = std::remove_pointer_t<T>;
112 return safe_clid_2<typ, ClassID_traits<typ>::s_isDataObject>::clid();