summaryrefslogtreecommitdiffstats
path: root/src/corelib/global/qttypetraits.qdoc
blob: ed814d6f431e66d39aeee9609c2cdbacc675a45c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only

/*!
    \headerfile <QtTypeTraits>
    \inmodule QtCore
    \since 6.5
    \title Qt Type Traits
    \brief Functionality for type traits and transformations.
*/

/*!
    \fn template <typename Enum> std::underlying_type_t<Enum> qToUnderlying(Enum e)
    \relates <QtTypeTraits>
    \since 6.2

    Converts the enumerator \a e to the equivalent value expressed in its
    enumeration's underlying type.
*/

/*!
    \fn template <typename T> typename std::add_const<T>::type &qAsConst(T &t)
    \relates <QtTypeTraits>
    \since 5.7

    \deprecated [6.6] Use std::as_const() instead.

    Returns \a t cast to \c{const T}.

    This function is a Qt implementation of C++17's std::as_const(),
    a cast function like std::move(). But while std::move() turns
    lvalues into rvalues, this function turns non-const lvalues into
    const lvalues. Like std::as_const(), it doesn't work on rvalues,
    because it cannot be efficiently implemented for rvalues without
    leaving dangling references.

    Its main use in Qt is to prevent implicitly-shared Qt containers
    from detaching:
    \snippet code/src_corelib_global_qglobal.cpp as-const-0

    Of course, in this case, you could (and probably should) have declared
    \c s as \c const in the first place:
    \snippet code/src_corelib_global_qglobal.cpp as-const-1
    but often that is not easily possible.

    It is important to note that qAsConst() does not copy its argument,
    it just performs a \c{const_cast<const T&>(t)}. This is also the reason
    why it is designed to fail for rvalues: The returned reference would go
    stale too soon. So while this works (but detaches the returned object):
    \snippet code/src_corelib_global_qglobal.cpp as-const-2

    this would not:
    \snippet code/src_corelib_global_qglobal.cpp as-const-3

    To prevent this construct from compiling (and failing at runtime), qAsConst() has
    a second, deleted, overload which binds to rvalues.

    \note You can make the qAsConst() function unavailable by defining
    the \l{QT_NO_QASCONST} macro.
*/

/*!
    \macro QT_NO_QASCONST
    \since 6.8
    \relates <QtTypeTraits>

    Defining this macro removes the availability of the qAsConst()
    function.

    \sa qAsConst
*/

/*!
    \fn template <typename T> void qAsConst(const T &&t)
    \relates <QtTypeTraits>
    \since 5.7
    \overload

    \deprecated [6.6]

    This overload is deleted to prevent a dangling reference in code like
    \snippet code/src_corelib_global_qglobal.cpp as-const-4
*/

/*!
    \fn template <typename T, typename U = T> T qExchange(T &obj, U &&newValue)
    \relates <QtTypeTraits>
    \since 5.14

    Replaces the value of \a obj with \a newValue and returns the old value of \a obj.

    This is Qt's implementation of std::exchange(). It differs from std::exchange()
    only in that it is \c constexpr already before C++20 and noexcept already before C++23.

    We strongly advise to use std::exchange() when you don't need the C++20 or C++23 variants.
    You can make qExchange() unavailable by defining the \l{QT_NO_QEXCHANGE} macro.

    Here is how to use qExchange() to implement move constructors:
    \code
    MyClass(MyClass &&other)
      : m_pointer{qExchange(other.m_pointer, nullptr)},
        m_int{qExchange(other.m_int, 0)},
        m_vector{std::move(other.m_vector)},
        ...
    \endcode

    For members of class type, we can use std::move(), as their move-constructor will
    do the right thing. But for scalar types such as raw pointers or integer type, move
    is the same as copy, which, particularly for pointers, is not what we expect. So, we
    cannot use std::move() for such types, but we can use std::exchange()/qExchange() to
    make sure the source object's member is already reset by the time we get to the
    initialization of our next data member, which might come in handy if the constructor
    exits with an exception.

    Here is how to use qExchange() to write a loop that consumes the collection it
    iterates over:
    \code
    for (auto &e : qExchange(collection, {})
        doSomethingWith(e);
    \endcode

    Which is equivalent to the following, much more verbose code:
    \code
    {
        auto tmp = std::move(collection);
        collection = {};                    // or collection.clear()
        for (auto &e : tmp)
            doSomethingWith(e);
    }                                       // destroys 'tmp'
    \endcode

    This is perfectly safe, as the for-loop keeps the result of qExchange() alive for as
    long as the loop runs, saving the declaration of a temporary variable. Be aware, though,
    that qExchange() returns a non-const object, so Qt containers may detach.
*/

/*!
    \macro QT_NO_QEXCHANGE
    \since 6.6
    \relates <QtTypeTraits>

    Defining this macro removes the availability of the qExchange()
    function.

    \sa qExchange
*/