Question

I'm trying to write a method that takes a class derived from std::string as an argument. The method is overloaded with several different function signatures. I'd like compilation to fail if I try to call it with a std::string, or at the very least a runtime error but apparently the compiler is too smart for me.

class NotAString : public std::string {
    NotAString(std::string str) : std::string(str) { }
};


class Foo {
   Foo();
   void bar(NotAString);
   void bar(int)
};

This compiles and runs

Foo foo();
foo.bar(NotAString("baz"));

But so does this:

Foo foo();
foo.bar(std::string("baz"));

I've tried using typeid(str) like so:

void Foo::Bar(NotAString str) {
    if(typeid(&str) != typeid(new NotAString()) {
        throw std::bad_typeid();
    }
}

But it always throws an exception if a pass it a std::string or NotAString. I've tried using a dynamic_cast like so:

void Foo::Bar(NotAString str) {
    if (dynamic_cast<NotAString*>(&str) == NULL) {
        throw std::bad_type();
    }
}

But it never throws an exception.

The goal is to be able to differentiate between a string and a string that represents a key for a key-value lookup. How can I change my NotAString class or enforce some more rigorous type checking by the compiler to get this to work how I would like?

Was it helpful?

Solution

The problem is your NotAString(std::string str) constuctor is not explicit so it allows implicit conversions from std::string to NotAString.

When you call the function with a std::string the compiler notices that you could call it by converting the argument via the constructor, so it creates a NotAString temporary and passes it to the function.

If you declare it explicit NotAString(std::string str) then it won't allow those implicit conversions.

Your attempts to check the type inside the function are never going to work, by that point the compiler has create a NotAString and all you're testing is whether a NotAString argument is not a NotAString ... which is obviously not going to work.

OTHER TIPS

Bad design ideas aside, change this constructor...

class NotAString : public std::string {
    NotAString(std::string str) : std::string(str) { }
};

...to be explicit:

class NotAString : public std::string {
    explicit NotAString(std::string str) : std::string(str) { }
};

That will prevent std::string objects from implcitly being converted to NotAString when they are used as a function parameter.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top