tags:

views:

103

answers:

1

I've been trying to get a template that converts the characters in a string to upper case letters.

I need to do this several times throughout my program.

So i'll use a template.

template <string theString>
string strUpper( string theString )
{
    int myLength = theString.length();
    for( int sIndex=0; sIndex < myLength; sIndex++ )
    {
        if ( 97 <= theString[sIndex] && theString[sIndex] <= 122 )
     {
     theString[sIndex] -= 32;
     }
    } 
   return theString;
}

now only if the template worked! Any Suggestions? The 'string' identifier should be an immediate flag.

+7  A: 

You apparently talk about C++ (no tags yet, so i'll think it is C++ here). Well you seem to want to say

As arguments to my template, i accept any type that models a string

Sadly, currently that is not possible yet. It requires the concept feature that will be in the next C++ version. Here is a video about them.

What you can do is accept basic_string<CharT, TraitsT> if you want to keep it generic, for example if you want to accept wide character strings aswell as narrow character strings

template <typename CharT, typename TraitsT>
std::basic_string<CharT, TraitsT> strUpper(basic_string<CharT, TraitsT> theString ) {
    typedef basic_string<CharT, TraitsT> StringT;
    for(typename StringT::iterator it = theString.begin(); 
        it != theString.end(); 
        ++it) 
    {
        *it = std::toupper(*it, std::locale());
    }   
    return theString;
}

It will not accept other or custom string classes that happen to be strings too. If you want that, keep it totally free of what it accepts and what not

template <typename StringT>
StringT strUpper(StringT theString) {
    for(typename StringT::iterator it = theString.begin(); 
        it != theString.end(); 
        ++it) 
    {
        *it = std::toupper(*it, std::locale());
    }   
    return theString;
}

You will have to tell the users of that library what functions and type they have to expose for that to work. The compiler will not know about that contract. Instead, it will just throw error messages when it comes to call the function with a type that's not a string. Often, you will find pages of error messages and it's difficult to get to the real reason of what goes wrong. The proposed Concepts feature for the next version of the standard fixes that nicely.

If you did not intend to write such a generic function, you can just go ahead and write a normal function like this

std::string strUpper(std::string theString) {
    for(std::string::iterator it = theString.begin(); 
        it != theString.end(); 
        ++it) 
    {
        *it = std::toupper(*it, std::locale());
    }   
    return theString;
}

If you did not intend to invent that function to learn in the first place, but because you did not find another already written algorithm, look into the boost string algorithm library. Then you can write

boost::algorithm::to_upper(mystring);
Johannes Schaub - litb
Pass std::string by const ref.
Mykola Golubyev
i will have to copy it anyway. it's better to take it by value because that will be more transparent to the caller and can be better optimized.
Johannes Schaub - litb
if i could optimize anything i could think of, then it's to create the locale object locally and always reuse it. right now i always create a new temporary one. but i think that are implementation questions. the guy will put it on the stack in his program.
Johannes Schaub - litb
in a real program i would probably do what the standard recommends: caching the ctype facet and its toupper function, saving the facet for later use: locale loc; ctype<T> const c.toupper(a) . This answer should show him the rough way i didn't want to bloat it :)
Johannes Schaub - litb