string builder: Fix ambiguity issues

This commit is contained in:
Martchus 2017-01-27 18:50:51 +01:00
parent 5eec3c3c9b
commit 5c004015ce
2 changed files with 68 additions and 12 deletions

View File

@ -12,47 +12,59 @@ namespace ConversionUtilities
/// \cond /// \cond
namespace Helper { namespace Helper {
template<class StringType, Traits::DisableIf<std::is_integral<StringType> > > template<class StringType, Traits::EnableIf<std::is_class<StringType> >...>
std::size_t computeTupleElementSize(const StringType *str) std::size_t computeTupleElementSize(const StringType *str)
{ {
return str->size(); return str->size();
} }
template<class StringType> template<class StringType, Traits::EnableIf<std::is_class<StringType> >...>
std::size_t computeTupleElementSize(const StringType &str) std::size_t computeTupleElementSize(const StringType &str)
{ {
return str.size(); return str.size();
} }
template<class CharType> template<class StringType, class CharType, Traits::EnableIf<std::is_same<typename StringType::value_type, CharType> >...>
std::size_t computeTupleElementSize(const CharType *str) std::size_t computeTupleElementSize(const CharType *str)
{ {
return std::char_traits<CharType>::length(str); return std::char_traits<CharType>::length(str);
} }
template<class StringType> template<class StringType, class CharType, Traits::EnableIf<std::is_same<typename StringType::value_type, CharType> >...>
constexpr std::size_t computeTupleElementSize(CharType)
{
return 1;
}
template<class StringType, Traits::EnableIf<std::is_class<StringType> >...>
void append(StringType &target, const StringType *str) void append(StringType &target, const StringType *str)
{ {
target.append(*str); target.append(*str);
} }
template<class StringType> template<class StringType, Traits::EnableIf<std::is_class<StringType> >...>
void append(StringType &target, const StringType &str) void append(StringType &target, const StringType &str)
{ {
target.append(str); target.append(str);
} }
template<class StringType, class CharType> template<class StringType, class CharType, Traits::EnableIf<std::is_same<typename StringType::value_type, CharType> >...>
void append(StringType &target, const CharType *str) void append(StringType &target, const CharType *str)
{ {
target.append(str); target.append(str);
} }
template<class StringType, class CharType, Traits::EnableIf<std::is_same<typename StringType::value_type, CharType> >...>
void append(StringType &target, CharType c)
{
target += c;
}
template<class StringType, class Tuple, std::size_t N> template<class StringType, class Tuple, std::size_t N>
struct TupleToString { struct TupleToString {
static std::size_t precomputeSize(const Tuple &tuple) static std::size_t precomputeSize(const Tuple &tuple)
{ {
return TupleToString<StringType, Tuple, N-1>::precomputeSize(tuple) + computeTupleElementSize(std::get<N-1>(tuple)); return TupleToString<StringType, Tuple, N-1>::precomputeSize(tuple) + computeTupleElementSize<StringType>(std::get<N-1>(tuple));
} }
static void append(const Tuple &tuple, StringType &str) static void append(const Tuple &tuple, StringType &str)
@ -66,7 +78,7 @@ template<class StringType, class Tuple>
struct TupleToString<StringType, Tuple, 1> { struct TupleToString<StringType, Tuple, 1> {
static std::size_t precomputeSize(const Tuple &tuple) static std::size_t precomputeSize(const Tuple &tuple)
{ {
return computeTupleElementSize(std::get<0>(tuple)); return computeTupleElementSize<StringType>(std::get<0>(tuple));
} }
static void append(const Tuple &tuple, StringType &str) static void append(const Tuple &tuple, StringType &str)
@ -125,6 +137,15 @@ constexpr auto operator %(const Tuple &lhs, const char *rhs) -> decltype(std::tu
return std::tuple_cat(lhs, std::make_tuple(rhs)); return std::tuple_cat(lhs, std::make_tuple(rhs));
} }
/*!
* \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3.
*/
template<class Tuple>
constexpr auto operator %(const Tuple &lhs, char rhs) -> decltype(std::tuple_cat(lhs, std::make_tuple(rhs)))
{
return std::tuple_cat(lhs, std::make_tuple(rhs));
}
/*! /*!
* \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3. * \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3.
*/ */
@ -149,6 +170,22 @@ constexpr auto operator %(const std::string &lhs, const char *rhs) -> decltype(s
return std::make_tuple(&lhs, rhs); return std::make_tuple(&lhs, rhs);
} }
/*!
* \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3.
*/
constexpr auto operator %(const std::string &lhs, char rhs) -> decltype(std::make_tuple(&lhs, rhs))
{
return std::make_tuple(&lhs, rhs);
}
/*!
* \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3.
*/
constexpr auto operator %(char lhs, const std::string &rhs) -> decltype(std::make_tuple(lhs, &rhs))
{
return std::make_tuple(lhs, &rhs);
}
/*! /*!
* \brief Allows construction of final string from previously constructed string-tuple and trailing string via +-operator. * \brief Allows construction of final string from previously constructed string-tuple and trailing string via +-operator.
* *
@ -158,7 +195,7 @@ constexpr auto operator %(const std::string &lhs, const char *rhs) -> decltype(s
* printVelocity("velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)")); * printVelocity("velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)"));
* ``` * ```
*/ */
template<class Tuple> template<class Tuple, Traits::DisableIfAny<std::is_same<Tuple, std::string>, std::is_same<Tuple, const char *>, std::is_array<Tuple>, std::is_same<Tuple, char> >...>
inline std::string operator +(const Tuple &lhs, const std::string &rhs) inline std::string operator +(const Tuple &lhs, const std::string &rhs)
{ {
return tupleToString(std::tuple_cat(lhs, std::make_tuple(&rhs))); return tupleToString(std::tuple_cat(lhs, std::make_tuple(&rhs)));
@ -173,12 +210,27 @@ inline std::string operator +(const Tuple &lhs, const std::string &rhs)
* printVelocity("velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)")); * printVelocity("velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)"));
* ``` * ```
*/ */
template<class Tuple> template<class Tuple, Traits::DisableIfAny<std::is_trivial<Tuple>, std::is_same<Tuple, std::string>, std::is_same<Tuple, const char *>, std::is_array<Tuple>, std::is_same<Tuple, char> >...>
inline std::string operator +(const Tuple &lhs, const char *rhs) inline std::string operator +(const Tuple &lhs, const char *rhs)
{ {
return tupleToString(std::tuple_cat(lhs, std::make_tuple(rhs))); return tupleToString(std::tuple_cat(lhs, std::make_tuple(rhs)));
} }
/*!
* \brief Allows construction of final string from previously constructed string-tuple and trailing char via +-operator.
*
* This is meant to be used for fast string building without multiple heap allocation, eg.
*
* ```
* printVelocity("velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)"));
* ```
*/
template<class Tuple, Traits::DisableIfAny<std::is_trivial<Tuple>, std::is_same<Tuple, std::string>, std::is_same<Tuple, const char *>, std::is_array<Tuple>, std::is_same<Tuple, char> >...>
inline std::string operator +(const Tuple &lhs, char rhs)
{
return tupleToString(std::tuple_cat(lhs, std::make_tuple(rhs)));
}
} }
#endif // CONVERSION_UTILITIES_STRINGBUILDER_H #endif // CONVERSION_UTILITIES_STRINGBUILDER_H

View File

@ -306,10 +306,14 @@ string functionTakingString(const string &str)
void ConversionTests::testStringBuilder() void ConversionTests::testStringBuilder()
{ {
// conversion of string-tuple to string (the actual string builder)
const tuple<const char *, string, const char *> tuple("string1", "string2", "string3"); const tuple<const char *, string, const char *> tuple("string1", "string2", "string3");
CPPUNIT_ASSERT_EQUAL(string("string1string2string3"), tupleToString(tuple)); CPPUNIT_ASSERT_EQUAL(string("string1string2string3"), tupleToString(tuple));
CPPUNIT_ASSERT_EQUAL(string("foobarfoo2bar2"), tupleToString(string("foo") % "bar" % string("foo2") % "bar2")); CPPUNIT_ASSERT_EQUAL(string("foobarfoo2bar2"), tupleToString(string("foo") % "bar" % string("foo2") % "bar2"));
CPPUNIT_ASSERT_EQUAL(string("123456"), functionTakingString("12" % string("34") + "56"));
// construction of string-tuple and final conversion to string works
CPPUNIT_ASSERT_EQUAL_MESSAGE("result can be passed to any function taking a std::string", string("1234567"), functionTakingString("12" % string("34") % '5' + "67"));
constexpr double velocityExample = 27.0; constexpr double velocityExample = 27.0;
CPPUNIT_ASSERT_EQUAL(string("velocity: 27 km/h (7.5 m/s)"), functionTakingString("velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)")); CPPUNIT_ASSERT_EQUAL_MESSAGE("real-word example", string("velocity: 27 km/h (7.5 m/s)"), functionTakingString("velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)"));
CPPUNIT_ASSERT_EQUAL_MESSAGE("regular + operator still works (no problems with ambiguity)", string("regular + still works"), string("regular") + " + still works");
} }