Skip to content
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
37 changes: 30 additions & 7 deletions include/wil/win32_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -971,17 +971,40 @@ bool init_once(_Inout_ INIT_ONCE& initOnce, T func)
/// @cond
namespace details
{
// NOTE: We can't have a 'using std::begin' at class scope, hence the workaround for handling both 'begin' with ADL
// and 'std::begin' separately. We want to handle both because there's no guarantee the type has a 'begin' method
template <typename RangeT>
struct deduce_char_type_from_string_range_traits
{
template <typename U>
static std::true_type deduce_has_adl_begin(U&& range, std::void_t<decltype((*begin(range))[0])>*);
template <typename U>
static std::false_type deduce_has_adl_begin(U&&, ...);

template <typename U>
static std::true_type deduce_has_std_begin(U&& range, std::void_t<decltype((*std::begin(range))[0])>*);
template <typename U>
static std::false_type deduce_has_std_begin(U&&, ...);

static constexpr bool has_adl_begin = decltype(deduce_has_adl_begin(std::declval<RangeT>(), nullptr))::value;
static constexpr bool has_std_begin = decltype(deduce_has_std_begin(std::declval<RangeT>(), nullptr))::value;
};

template <typename RangeT, bool hasAdlBegin = deduce_char_type_from_string_range_traits<RangeT>::has_adl_begin, bool hasStdBegin = deduce_char_type_from_string_range_traits<RangeT>::has_std_begin>
struct deduce_char_type_from_string_range
{
template <typename T = RangeT>
static auto deduce(T& range)
{
using std::begin;
return (*begin(range))[0];
}
};

using type = decltype(deduce(wistd::declval<RangeT&>()));
template <typename RangeT, bool hasStdBegin>
struct deduce_char_type_from_string_range<RangeT, true, hasStdBegin>
{
using type = std::decay_t<decltype((*begin(std::declval<RangeT>()))[0])>;
};

template <typename RangeT>
struct deduce_char_type_from_string_range<RangeT, false, true>
{
using type = std::decay_t<decltype((*std::begin(std::declval<RangeT>()))[0])>;
};

template <typename RangeT>
Expand Down
5 changes: 5 additions & 0 deletions tests/wiTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4225,6 +4225,11 @@ TEST_CASE("WindowsInternalTests::ArgvToCommandLine", "[win32_helpers]")
{L"test", L"This\u00A0string\u180Ehas\u2000no\u2001space\u2002characters\u2003even\u2004though\u2005it\u2006contains\u2007characters\u2008that\u2009look\u200Athe\u200Bsame\u200Cor\u200Dare\u202Fsometimes\u205Ftreated\u2060the\u2800same\u3000as\u3164whitespace"},
L"test This\u00A0string\u180Ehas\u2000no\u2001space\u2002characters\u2003even\u2004though\u2005it\u2006contains\u2007characters\u2008that\u2009look\u200Athe\u200Bsame\u200Cor\u200Dare\u202Fsometimes\u205Ftreated\u2060the\u2800same\u3000as\u3164whitespace",
L"\"test\" \"This\u00A0string\u180Ehas\u2000no\u2001space\u2002characters\u2003even\u2004though\u2005it\u2006contains\u2007characters\u2008that\u2009look\u200Athe\u200Bsame\u200Cor\u200Dare\u202Fsometimes\u205Ftreated\u2060the\u2800same\u3000as\u3164whitespace\"");

// Finally, ensure that we can call the argc+argv version using the default flags
const char* const argvArray[] = {"test.exe", "foo", "bar"}; // Simple... this is just to verify we can call it
auto cmdLine = wil::ArgvToCommandLine(3, argvArray);
REQUIRE(cmdLine == "test.exe foo bar");
}
#endif

Expand Down