5

Suppose I have this function to trim an std::string and decide to extend it, so that it removes not only spaces from the beginning and end, but also any character I pass in another string, like spaces, newlines and carriage returns.

std::string Trim ( const std::string &In_Original,
  const std::string &In_CharsToTrim = " \n\r" );

So basically, it would remove all characters present in In_CharsToTrim from the beginning and end of In_Original.

Now, I had to write this for both std::string and std::wstring. Since I find that absurd, I chose to make use of templates, and it works, but I am unable to pass a default value, because the std::wstring version must get L" \n\r" as the default value (note that little L, there).

I tried this:

template <typename Type> Type Trim ( const Type &In_String,
  const Type &In_TrimCharacters );

along with:

template std::string Trim ( const  std::string &In_String,
  const  std::string &In_TrimCharacters = " \n\r" );
template std::wstring Trim ( const  std::wstring &In_String,
  const  std::wstring &In_TrimCharacters = L" \n\r" );

But it didn't work. It doesn't even compile.

Currently, what I have, is a separate function for when you call without a second parameter, but this is completely the wrong approach:

template <typename Type> Type Trim ( const Type &In_String,
  const Type &In_TrimCharacters );
std::string Trim ( const std::string &In_String );
std::wstring Trim ( const std::wstring &In_String );

Then, in this simpler Trim function, I'm simply calling the complete version.

So, basically, what I'm asking is this...:

How can I pass a different default value depending on the template type? Basically, a specialization, in which the only change is the default parameter...

In this case, to pass std::string ( " \n\r" ) in one case, and std::wstring ( L" \n\r" ) in the other...

Or... is there another way to do what I'm trying to do, here?

3 Answers 3

6

This is what I come up with:

template <typename T> struct default_trim_chars;

template<> struct default_trim_chars<std::string> { 
    static const char* value() { return " \n\r"; }
};

template<> struct default_trim_chars<std::wstring> { 
    static const wchar_t* value() { return L" \n\r"; }
};

template <typename Type> Type Trim ( const Type &In_String,
const Type &In_TrimCharacters = default_trim_chars<Type>::value()){
    /* ... */
}

You can also declare value as a data member instead of a function, but that would require constexpr and C++11.

Sign up to request clarification or add additional context in comments.

1 Comment

This solution worked without changing compiler options, which was a must. Thanks!
3

You can use a simple trait class and using its ::value as the default argument.

template<typename T>
struct type_sensitive_default_argument;

template<>
struct type_sensitive_default_argument<std::string>
{
     static constexpr char value[] = "\n\r";
};

template<>
struct type_sensitive_default_argument<std::wstring>
{
    static constexpr wchar_t value[] = L"\n\r";
};

Then you can do:

template<class Type,
         class Default = type_sensitive_default_argument<Type>>
Type Trim(const Type& In_String,
          const Type& In_TrimCharacters = Default::value);

2 Comments

For some reason, i am unable to compile that code. It does not recognize constexpr. I replaced it with simply const, and of course, it complained that i'm initializing a const member variable inside the class declaration. So i removed the initialization, and put it outside the declaration, and the i hit a brick wall. I got this: error: default template arguments may not be used in function templates without -std=c++11 or -std=gnu++11
I guess all of the above errors are because i'm still using C99... bummer. I'll try and see what the differences are, to see if it's possible to change the compiler settings, without much trouble..
1

In your case you might rely on specifying an initializer list of characters to do the conversion for you:

template <typename Type> Type Trim ( const Type &In_String,
  const Type &In_TrimCharacters = { ' ', '\r', '\n' } )
{
    // ...
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.