From ee851c7e880abbee0a5fb78b77606cc0d8862883 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Fri, 31 Jan 2020 04:49:40 -0800 Subject: [PATCH] String conversions (#421) * add a variant of the string conversions for the default string operations. Discriminate between the is_convertible and is_constructible type traits for object. * update the test to test the different situations with the funny string like type --- include/CLI/TypeTools.hpp | 15 ++++++++++++--- tests/AppTest.cpp | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/include/CLI/TypeTools.hpp b/include/CLI/TypeTools.hpp index fe8a04b7..023edd73 100644 --- a/include/CLI/TypeTools.hpp +++ b/include/CLI/TypeTools.hpp @@ -219,15 +219,24 @@ template class is_tuple_like { }; /// Convert an object to a string (directly forward if this can become a string) -template ::value, detail::enabler> = detail::dummy> +template ::value, detail::enabler> = detail::dummy> auto to_string(T &&value) -> decltype(std::forward(value)) { return std::forward(value); } +/// Construct a string from the object +template ::value && !std::is_convertible::value, + detail::enabler> = detail::dummy> +std::string to_string(const T &value) { + return std::string(value); +} + /// Convert an object to a string (streaming must be supported for that type) template ::value && is_ostreamable::value, detail::enabler> = - detail::dummy> + enable_if_t::value && !std::is_constructible::value && + is_ostreamable::value, + detail::enabler> = detail::dummy> std::string to_string(T &&value) { std::stringstream stream; stream << value; diff --git a/tests/AppTest.cpp b/tests/AppTest.cpp index d3aa8375..633072ee 100644 --- a/tests/AppTest.cpp +++ b/tests/AppTest.cpp @@ -1885,6 +1885,27 @@ TEST_F(TApp, VectorUnlimString) { EXPECT_EQ(answer, strvec); } +// From https://github.com/CLIUtils/CLI11/issues/420 +TEST_F(TApp, stringLikeTests) { + struct nType { + explicit nType(const std::string &a_value) : m_value{a_value} {} + + explicit operator std::string() const { return std::string{"op str"}; } + + std::string m_value; + }; + + nType m_type{"abc"}; + app.add_option("--type", m_type, "type")->capture_default_str(); + run(); + + EXPECT_EQ(app["--type"]->as(), "op str"); + args = {"--type", "bca"}; + run(); + EXPECT_EQ(std::string(m_type), "op str"); + EXPECT_EQ(m_type.m_value, "bca"); +} + TEST_F(TApp, VectorExpectedRange) { std::vector strvec;