Reputation: 67
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?
Upvotes: 0
Views: 142
Reputation: 171263
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.
Upvotes: 2
Reputation: 63775
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.
Upvotes: 0