PageRenderTime 22ms CodeModel.GetById 13ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/llcommon/ll_template_cast.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 177 lines | 33 code | 6 blank | 138 comment | 0 complexity | 5821f8fd560ef44bb10c7bf0390a6179 MD5 | raw file
  1/**
  2 * @file   ll_template_cast.h
  3 * @author Nat Goodspeed
  4 * @date   2009-11-21
  5 * @brief  Define ll_template_cast function
  6 * 
  7 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  8 * Second Life Viewer Source Code
  9 * Copyright (C) 2010, Linden Research, Inc.
 10 * 
 11 * This library is free software; you can redistribute it and/or
 12 * modify it under the terms of the GNU Lesser General Public
 13 * License as published by the Free Software Foundation;
 14 * version 2.1 of the License only.
 15 * 
 16 * This library is distributed in the hope that it will be useful,
 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19 * Lesser General Public License for more details.
 20 * 
 21 * You should have received a copy of the GNU Lesser General Public
 22 * License along with this library; if not, write to the Free Software
 23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 24 * 
 25 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 26 * $/LicenseInfo$
 27 */
 28
 29#if ! defined(LL_LL_TEMPLATE_CAST_H)
 30#define LL_LL_TEMPLATE_CAST_H
 31
 32/**
 33 * Implementation for ll_template_cast() (q.v.).
 34 *
 35 * Default implementation: trying to cast two completely unrelated types
 36 * returns 0. Typically you'd specify T and U as pointer types, but in fact T
 37 * can be any type that can be initialized with 0.
 38 */
 39template <typename T, typename U>
 40struct ll_template_cast_impl
 41{
 42    T operator()(U)
 43    {
 44        return 0;
 45    }
 46};
 47
 48/**
 49 * ll_template_cast<T>(some_value) is for use in a template function when
 50 * some_value might be of arbitrary type, but you want to recognize type T
 51 * specially.
 52 *
 53 * It's designed for use with pointer types. Example:
 54 * @code
 55 * struct SpecialClass
 56 * {
 57 *     void someMethod(const std::string&) const;
 58 * };
 59 *
 60 * template <class REALCLASS>
 61 * void somefunc(const REALCLASS& instance)
 62 * {
 63 *     const SpecialClass* ptr = ll_template_cast<const SpecialClass*>(&instance);
 64 *     if (ptr)
 65 *     {
 66 *         ptr->someMethod("Call method only available on SpecialClass");
 67 *     }
 68 * }
 69 * @endcode
 70 *
 71 * Why is this better than dynamic_cast<>? Because unless OtherClass is
 72 * polymorphic, the following won't even compile (gcc 4.0.1):
 73 * @code
 74 * OtherClass other;
 75 * SpecialClass* ptr = dynamic_cast<SpecialClass*>(&other);
 76 * @endcode
 77 * to say nothing of this:
 78 * @code
 79 * void function(int);
 80 * SpecialClass* ptr = dynamic_cast<SpecialClass*>(&function);
 81 * @endcode
 82 * ll_template_cast handles these kinds of cases by returning 0.
 83 */
 84template <typename T, typename U>
 85T ll_template_cast(U value)
 86{
 87    return ll_template_cast_impl<T, U>()(value);
 88}
 89
 90/**
 91 * Implementation for ll_template_cast() (q.v.).
 92 *
 93 * Implementation for identical types: return same value.
 94 */
 95template <typename T>
 96struct ll_template_cast_impl<T, T>
 97{
 98    T operator()(T value)
 99    {
100        return value;
101    }
102};
103
104/**
105 * LL_TEMPLATE_CONVERTIBLE(dest, source) asserts that, for a value @c s of
106 * type @c source, <tt>ll_template_cast<dest>(s)</tt> will return @c s --
107 * presuming that @c source can be converted to @c dest by the normal rules of
108 * C++.
109 *
110 * By default, <tt>ll_template_cast<dest>(s)</tt> will return 0 unless @c s's
111 * type is literally identical to @c dest. (This is because of the
112 * straightforward application of template specialization rules.) That can
113 * lead to surprising results, e.g.:
114 *
115 * @code
116 * Foo myFoo;
117 * const Foo* fooptr = ll_template_cast<const Foo*>(&myFoo);
118 * @endcode
119 *
120 * Here @c fooptr will be 0 because <tt>&myFoo</tt> is of type <tt>Foo*</tt>
121 * -- @em not <tt>const Foo*</tt>. (Declaring <tt>const Foo myFoo;</tt> would
122 * force the compiler to do the right thing.)
123 *
124 * More disappointingly:
125 * @code
126 * struct Base {};
127 * struct Subclass: public Base {};
128 * Subclass object;
129 * Base* ptr = ll_template_cast<Base*>(&object);
130 * @endcode
131 *
132 * Here @c ptr will be 0 because <tt>&object</tt> is of type
133 * <tt>Subclass*</tt> rather than <tt>Base*</tt>. We @em want this cast to
134 * succeed, but without our help ll_template_cast can't recognize it.
135 *
136 * The following would suffice:
137 * @code
138 * LL_TEMPLATE_CONVERTIBLE(Base*, Subclass*);
139 * ...
140 * Base* ptr = ll_template_cast<Base*>(&object);
141 * @endcode
142 *
143 * However, as noted earlier, this is easily fooled:
144 * @code
145 * const Base* ptr = ll_template_cast<const Base*>(&object);
146 * @endcode
147 * would still produce 0 because we haven't yet seen:
148 * @code
149 * LL_TEMPLATE_CONVERTIBLE(const Base*, Subclass*);
150 * @endcode
151 *
152 * @TODO
153 * This macro should use Boost type_traits facilities for stripping and
154 * re-adding @c const and @c volatile qualifiers so that invoking
155 * LL_TEMPLATE_CONVERTIBLE(dest, source) will automatically generate all
156 * permitted permutations. It's really not fair to the coder to require
157 * separate:
158 * @code
159 * LL_TEMPLATE_CONVERTIBLE(Base*, Subclass*);
160 * LL_TEMPLATE_CONVERTIBLE(const Base*, Subclass*);
161 * LL_TEMPLATE_CONVERTIBLE(const Base*, const Subclass*);
162 * @endcode
163 *
164 * (Naturally we omit <tt>LL_TEMPLATE_CONVERTIBLE(Base*, const Subclass*)</tt>
165 * because that's not permitted by normal C++ assignment anyway.)
166 */
167#define LL_TEMPLATE_CONVERTIBLE(DEST, SOURCE)   \
168template <>                                     \
169struct ll_template_cast_impl<DEST, SOURCE>      \
170{                                               \
171    DEST operator()(SOURCE wrapper)             \
172    {                                           \
173        return wrapper;                         \
174    }                                           \
175}
176
177#endif /* ! defined(LL_LL_TEMPLATE_CAST_H) */