Skip to content

Commit

Permalink
Merge pull request #100426 from Ivorforce/variant-move-constructor
Browse files Browse the repository at this point in the history
Add move assignment and move constructor to Variant.
  • Loading branch information
Repiteo committed Dec 16, 2024
2 parents ea351e4 + 34fa0bf commit e42c22f
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 1 deletion.
35 changes: 34 additions & 1 deletion core/object/make_virtuals.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def generate_version(argcount, const=False, returns=False, required=False):
callptrargsptr += ", "
argtext += f"m_type{i + 1}"
callargtext += f"m_type{i + 1} arg{i + 1}"
callsiargs += f"Variant(arg{i + 1})"
callsiargs += f"_to_variant(arg{i + 1})"
callsiargptrs += f"&vargs[{i}]"
callptrargs += (
f"PtrToArg<m_type{i + 1}>::EncodeT argval{i + 1} = (PtrToArg<m_type{i + 1}>::EncodeT)arg{i + 1};\\\n"
Expand Down Expand Up @@ -185,6 +185,8 @@ def run(target, source, env):
#include "core/object/script_instance.h"
#include <utility>
#ifdef TOOLS_ENABLED
#define GDVIRTUAL_TRACK(m_virtual, m_initialized)\\
if (_get_extension()->reloadable) {\\
Expand All @@ -198,6 +200,37 @@ def run(target, source, env):
#define GDVIRTUAL_TRACK(m_virtual, m_initialized)
#endif
// MSVC WORKAROUND START
// FIXME The below helper functions are needed to work around an MSVC bug.
// They should be removed (by modifying core/object/make_virtuals.py) once the bug ceases to be triggered.
// The bug is triggered by the following code:
// `Variant(arg)`
// Through the introduction of the move constructor, MSVC forgets that `operator Variant()`
// is also a valid way to resolve this call. So for some argument types, it fails the call because
// it cannot convert to `Variant`.
// The function `_to_variant` helps the compiler select `.operator Variant()` for appropriate arguments using SFINAE.
template <typename T, typename = void>
struct has_variant_operator : std::false_type {};
template <typename T>
struct has_variant_operator<T, std::void_t<decltype(std::declval<T>().operator Variant())>> : std::true_type {};
// Function that is enabled if T has `.operator Variant()`.
template <typename T>
_ALWAYS_INLINE_ typename std::enable_if<has_variant_operator<T>::value, Variant>::type
_to_variant(T&& t) {
return std::forward<T>(t).operator Variant();
}
// Function that is enabled if T does not have `.operator Variant()`.
template <typename T>
_ALWAYS_INLINE_ typename std::enable_if<!has_variant_operator<T>::value, Variant>::type
_to_variant(T&& t) {
return Variant(std::forward<T>(t));
}
// MSVC WORKAROUND END
"""

for i in range(max_versions + 1):
Expand Down
14 changes: 14 additions & 0 deletions core/variant/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -811,11 +811,25 @@ class Variant {
static void construct_from_string(const String &p_string, Variant &r_value, ObjectConstruct p_obj_construct = nullptr, void *p_construct_ud = nullptr);

void operator=(const Variant &p_variant); // only this is enough for all the other types
void operator=(Variant &&p_variant) {
if (unlikely(this == &p_variant)) {
return;
}
clear();
type = p_variant.type;
_data = p_variant._data;
p_variant.type = NIL;
}

static void register_types();
static void unregister_types();

Variant(const Variant &p_variant);
Variant(Variant &&p_variant) {
type = p_variant.type;
_data = p_variant._data;
p_variant.type = NIL;
}
_FORCE_INLINE_ Variant() {}
_FORCE_INLINE_ ~Variant() {
clear();
Expand Down

0 comments on commit e42c22f

Please sign in to comment.