views:

164

answers:

3

I have a method that effectively takes a string. However, there is a very limited subset of strings I want to use. I was thinking of typedef'ing std::string as some class, and call the functions explicit. I'm not sure that would work, however. Ideas?

+6  A: 

It sounds like you want to limit the inputs (i.e. perhaps a string that only allows letters).

I would recommend using a string within a class and then wrapping the functions you want.

class limited_string
{
    std::string str;

public:
    limited_string(const char *data)
        : str(data)
    {
        if (!valid(str))
            throw std::runtime_exception(); 
    }

    virtual ~limited_string() {}

    limited_string &operator+=(const char *data)
    {
        // do all your work on the side - this way you don't have to rollback
        // if the newly created string is invalid
        std::string newstr(str);
        newstr += data;
        if (!valid(newstr))
            throw std::runtime_exception();

        str = newstr;
    }

    virtual bool valid(const std::string str) = 0;
}
R Samuel Klatchko
+1 for a concrete example
Bill
I would make your `operator+=` take a non-const `std::string`. This doubles as your `newstr`, and allows it to accept `std::string`s as well.
GMan
+7  A: 

The usual rule still applies: the class isn't designed to be inherited from, and its destructor isn't virtual, so if you ever upcast to the std::string base class, and let the object be destroyed, your derived class' destructor won't be called.

If you can guarantee that this will never happen, go ahead.

Otherwise, you could make the std::string a member of your class, rather than a base class. or you could use private inheritance. The problem with this approach is that you'd have to re-implement the string interface for the class to be usable as a string.

Or you could just define your class to expose a getString() function which returns the internal std::string object. Then you can still pass your own class around, and the compiler will complain if you try to pass a std::string, but the internal string is accessible when you need it. That might be the best compromise.

jalf
A: 

It sounds like you have one method which accepts a restricted string. Is a new class really necessary?

void needs_restricted_string( std::string const &str ) {
    if ( ! is_restricted_string( str ) ) throw std::runtime_error( "bad str" );
    …
}

Otherwise, the only thing you want to capture is whether a string satisfies the restrictions. The only difference I see between is_restricted_string() and a compile-time class is performance, in the case you have a storage structure dedicated to checked strings. Don't prematurely optimize. That said, it would also be an error to put too much functionality into your new class or to use it like a string.

class restricted_string {
    std::string storage;
public:
     // constructor may implement move or swap() semantics for performance
     // it throws if string is no good
     // not explicit, may be called for implicit conversion
    restricted_string( std::string const & ) throw runtime_error;
     // getter should perhaps be private with needs_restricted as friend
    std::string const &str() const { return storage; }
}; // and no more functionality than that!

void needs_restricted_string( restricted_string const &str ) {
    std::string const &known_restricted = str.str();
}

std::string mystr( "hello" );
needs_restricted_string( mystr );
Potatoswatter