cytrinox
cytrinox

Reputation: 1946

Create strings depending on template arguments

I have many classes/methods like this:

template<typename CharT, typename TraitsT = std::char_traits<CharT> >
struct Foo
{
   std::basic_string<CharT, TraitsT> getFoo(void) const
   {
     return "Foo"; // + this->member_var1 + this->member_var2...
   }
};

But depending on CharT, I have to use "", L"", u"" or "U" (for char, wchar_t, u16char_t, u32char_t).

What syntax must be used to create strings that are independed from such template arguments?

Upvotes: 14

Views: 874

Answers (3)

usta
usta

Reputation: 6869

Here is a solution using a MACRO

template < typename CharT >
struct char_t_literal_selector;

template <>
struct char_t_literal_selector< char > {
    static const char *select( const char *s, const wchar_t *, const char16_t *, const char32_t * )
    {
        return s;
    }
};

template <>
struct char_t_literal_selector< wchar_t > {
    static const wchar_t *select( const char *, const wchar_t *s, const char16_t *, const char32_t * )
    {
        return s;
    }
};

template <>
struct char_t_literal_selector< char16_t > {
    static const char16_t *select( const char *, const wchar_t *, const char16_t *s, const char32_t * )
    {
        return s;
    }
};

template <>
struct char_t_literal_selector< char32_t > {
    static const char32_t *select( const char *, const wchar_t *, const char16_t *, const char32_t *s )
    {
        return s;
    }
};

#define CHART_LITERAL(str) ( char_t_literal_selector< CharT >::select( str, L ## str, u ## str, U ## str ) )


template<typename CharT, typename TraitsT = std::char_traits<CharT> >
struct Foo
{
   std::basic_string<CharT, TraitsT> getFoo(void) const
   {
     return CHART_LITERAL("Foo"); // + this->member_var1 + this->member_var2...
   }
};

assuming the template parameter name is always CharT. If it is not, add another parameter to the macro. HTH

Upvotes: 1

Steve M
Steve M

Reputation: 8526

If you're going to be appending things to the string anyhow, use a stringstream:

std::basic_string<CharT, TraitsT> getFoo(void) const
{
  std::basic_ostringstream<CharT, TraitsT> os;
  os << "Foo";
  // os << this->member_var1 << this->member_var2...
  return os.str();
}

I like Steve Jessop's answer, too.

Upvotes: 1

Steve Jessop
Steve Jessop

Reputation: 279455

Do you really need the different literals, or can you use the iterator constructor?

const char *f = "Foo";
return std::basic_string<CharT, TraitsT>(f, f + 3);

Maybe with something a bit more robust than "3" in there, if you're worried about ease of changing the literal in future.

In response to the point that this isn't very nice, what about:

template <typename CharT, typename TraitsT, size_t N>
basic_string<CharT, TraitsT> proper_string(const char (&src)[N]) {
    return basic_string<CharT, TraitsT>(src, src+N-1);
}

Then you have:

return proper_string<CharT, TraitsT>("Foo");

If you really need the different literal, then the only thing I've thought of so far is to create traits for it, which is really horrible:

template<typename T> struct FooString {
};

template<> struct FooString<char> {
    static const char *value() { return "Foo"; }
};
template<> struct FooString<wchar_t> {
    static const wchar_t *value() { return L"Foo"; }
};
... etc ...

return FooString<CharT>::value();

Upvotes: 7

Related Questions