diff --git a/include/wil/win32_helpers.h b/include/wil/win32_helpers.h index 9457eb03..a9d2f1ee 100644 --- a/include/wil/win32_helpers.h +++ b/include/wil/win32_helpers.h @@ -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 + struct deduce_char_type_from_string_range_traits + { + template + static std::true_type deduce_has_adl_begin(U&& range, std::void_t*); + template + static std::false_type deduce_has_adl_begin(U&&, ...); + + template + static std::true_type deduce_has_std_begin(U&& range, std::void_t*); + template + static std::false_type deduce_has_std_begin(U&&, ...); + + static constexpr bool has_adl_begin = decltype(deduce_has_adl_begin(std::declval(), nullptr))::value; + static constexpr bool has_std_begin = decltype(deduce_has_std_begin(std::declval(), nullptr))::value; + }; + + template ::has_adl_begin, bool hasStdBegin = deduce_char_type_from_string_range_traits::has_std_begin> struct deduce_char_type_from_string_range { - template - static auto deduce(T& range) - { - using std::begin; - return (*begin(range))[0]; - } + }; - using type = decltype(deduce(wistd::declval())); + template + struct deduce_char_type_from_string_range + { + using type = std::decay_t()))[0])>; + }; + + template + struct deduce_char_type_from_string_range + { + using type = std::decay_t()))[0])>; }; template diff --git a/tests/wiTest.cpp b/tests/wiTest.cpp index ffcbb60c..e33f3da3 100644 --- a/tests/wiTest.cpp +++ b/tests/wiTest.cpp @@ -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