Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

variant constructor and assignment shouldn't allow narrow conversion #463

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions include/EASTL/meta.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,17 +181,21 @@ namespace eastl
// overload_resolution has selected a function to run.
//

// Helper used to check for valid conversions that don't involve narrowing.
template <class T>
T make_overload_array(T(&&)[1]);

// a single overload of an individual type
template <typename T>
struct overload
{
// Overload is implicitly convertible to the surrogated function
// call for pointer to member functions (pmf). This gets around
// variadic pack expansion in a class using statement being a C++17
// language feature. It is the core mechanism of aggregating all the
// Overload is a functor that will be selected by overload resolution
// if and only if there's no narrow conversion to convert ParamType into T.
// This gets around variadic pack expansion in a class using statement being
// a C++17 language feature. It is the core mechanism of aggregating all the
// individual overloads into the overload_set structure.
using F = T (*)(T);
operator F() const { return nullptr; }
template <class ParamType, typename = decltype(make_overload_array<T>({declval<ParamType>()}))>
T operator()(T, ParamType&&);
};

template <typename...> struct overload_set_impl;
Expand All @@ -206,7 +210,9 @@ namespace eastl
};

EA_DISABLE_VC_WARNING(4242 4244) // conversion from 'T' to 'U', possible loss of data.
template <typename T, typename OverloadSet, typename ResultT = decltype(declval<OverloadSet>()(declval<T>()))>
template <typename T,
typename OverloadSet,
typename ResultT = decltype(declval<OverloadSet>()(declval<T>(), declval<T>()))>
struct overload_resolution
{
// capture the return type of the function the compiler selected by
Expand Down
2 changes: 1 addition & 1 deletion test/source/TestMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ int TestOverloadResolution()
int nErrorCount = 0;

static_assert(is_same_v<overload_resolution_t<int, overload_set<int>>, int>, "error");
static_assert(is_same_v<overload_resolution_t<int, overload_set<short>>, short>, "error");
static_assert(is_same_v<overload_resolution_t<int, overload_set<long>>, long>, "error");
static_assert(is_same_v<overload_resolution_t<short, overload_set<int>>, int>, "error");
static_assert(is_same_v<overload_resolution_t<int, overload_set<int, short, long>>, int>, "error");
static_assert(is_same_v<overload_resolution_t<int, overload_set<short, int, long, float>>, int>, "error");
static_assert(is_same_v<overload_resolution_t<int, overload_set<short, long, int, float, char>>, int>, "error");
static_assert(is_same_v<overload_resolution_t<int, overload_set<float, int, double>>, int>, "error");

static_assert(is_same_v<overload_resolution_t<int, overload_set<int>>, int>, "error");
static_assert(is_same_v<overload_resolution_t<int, overload_set<int, short>>, int>, "error");
Expand Down
12 changes: 12 additions & 0 deletions test/source/TestVariant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,18 @@ int TestVariantBasic()
VERIFY(*(get_if<string>(&v)) == "a");
}

{
// verify construction where only one candidate doesn't require narrow conversion
variant<float, long, double> v = 42;
VERIFY(holds_alternative<long>(v));
VERIFY(get<long>(v) == 42);

// and assignment operator=
v = 43;
VERIFY(holds_alternative<long>(v));
VERIFY(get<long>(v) == 43);
}

return nErrorCount;
}

Expand Down