That was kindof the point, wasn't it?
So, you have an example?
I'd love to see you thwart the happy little compiler.
Printable View
I do not see what "it isn't a counter" has to do with anything. Concerning the error: I ignored that part due to the disclaimer that only C++ Coding Standards incorporates corrections, but thinking about it further, it cuts both ways: suppose the constructor that creates a string with n characters was changed such that the null character was default. In that case, implicit conversion would allow Sutter's otherwise problematic original example to compile when the conversion function is provided.Quote:
Originally Posted by phantomotap
Precisely, though more generally, "to block otherwise logically illegal, or just silly, operations", as you yourself have pointed out much earlier.Quote:
Originally Posted by phantomotap
That is easier said than done. Providing a named conversion function, on the other hand, is as easily done as said, and avoids those problems associated with implicit conversions.Quote:
Originally Posted by phantomotap
O_oQuote:
I'd love to see you thwart the happy little compiler.
Thwart the compiler?! Are you insane?! I'm suggesting you use the compiler. That's why it exists. What don't you get? You can literally use any method of static assertion or compiler firewall you desire.
As I've implied: I use a meta-function to do this for any or all of the operators applied to any number of types--actually limited to 64. The massive overhead would be pointless, but I'll offer a trivial and sloppy way to block an operator for a type you don't own without otherwise affecting the compiler output, messages or errors, from "correct" source. Enjoy.
No. It isn't. I have a series of meta-functions that you simply invoke. (That is, it is as easy done as typed.)Quote:
That is easier said than done.
Soma
Code:class blocker{public: blocker(){} private:blocker(const blocker &){} friend blocker operator - (const my_string &, const my_string &);};
blocker operator -
(
const my_string & lhs,
const my_string & rhs
)
{
blocker return_value;
return(return_value);
}
You still have to determine what to invoke, and have to update your code if there are additions to the target type interface (for class types not under your control, at least), even if these would not normally affect your code.Quote:
Originally Posted by phantomotap
O_oQuote:
In my view, you are opening up evil conversion with the implicit type operator, but then you are blocking them...
Yea... that would be silly, but I'm not blocking the conversion. I'm telling the compiler that certain constructs are invalid... I'm basically marking conversions in certain contexts as private.
If your code would not be affected by such additions then, by definition, no source change would be needed regardless of the source written to prevent such constructs from compiling. (Edit: Actually, I may be giving to much credit here; it is possible to write source that depends upon the firewall for correct compilation, but it is very unlikely to happen by accident.) That said, if you desire that your source makes use of these additional facilities, you would have to change something, but that's always the case.Quote:
You still have to determine what to invoke, and have to update your code if there are additions to the target type interface (for class types not control your control, at least), even if these would not normally affect your code.
Soma
Yes, it is like declaring copy constructors and copy assignment operators private in order to disable copying.Quote:
Originally Posted by phantomotap
Ah, but what if the type you are designing is intended for use (or just might be used) by another programmer (or team, as the case may be), as would be the case for a library? Such a source code change would be needed in order to maintain the interface provided.Quote:
Originally Posted by phantomotap
When you put it as "additional facilities", I tend to agree with the notion that this would be a viable alternative to a named conversion function, though I am not convinced that it is worth the effort when a named conversion function can be clearer and just shifts the burden on using sensible operations from other types to the user of the type you provide.Quote:
Originally Posted by phantomotap
O_oQuote:
When you put it as "additional facilities", I tend to agree with the notion that this would be a viable alternative to a named conversion function, though I am not convinced that it is worth the effort when a named conversion function can be clearer and just shifts the burden on using sensible operations from other types to the user of the type you provide.
I think I've spotted a flaw in your understanding. In a perfect world the responsibility, or burden if you like, of disabling conversions for specific constructs belongs to the provider of a type. (You wouldn't, or shouldn't, in using my library, or any other, go into the headers to mark some method private even if it should have been marked private.) Even in our world of shambles, the responsibility belongs to a single type. (Granted, in this case I've offered that it can "fix" an existing provision that didn't account for unwanted implicit conversion by displacing this burden, but that's not really the point.) The relevant source, even without templates, need only be written to disallow problematic conversions for each implicitly converted type for any given class type with such implicit conversions. The 'blocking' type is a "no-op"; it is no more associated with the relevant type nor any more responsible than 'std::string' would be if someone provides 'std::string operator + (const std::vector<?> &, unsigned long)'.
Soma
PS. And not that it matters, but I'm a big fan of consistency. I teach people to use 'static_cast<?>' even with classes offering implicit conversion. (With an exception of 'operator void *' and 'operator bool' because stream using source seems "right" without it.)
It is interesting that you start by saying
and you finish with thisQuote:
No. They should not be avoided. If you do the work to block otherwise logically illegal, or just silly, operations they can make code much cleaner. (Of course, misused they can make code uglier, but that doesn't say much as it applies to most features of C++.)
So you would prefer:Quote:
PS. And not that it matters, but I'm a big fan of consistency. I teach people to use 'static_cast<?>' even with classes offering implicit conversion. (With an exception of 'operator void *' and 'operator bool' because stream using source seems "right" without it.)
Does this apply only to string-like things? Many classes can return objects of various types from different methods, would you also make the classes castable into these types?Code:ofsteam fout(static_cast<const char*>(filename));
//over
ofstream fout(filename.c_str());
Code:Character c;
//Rect r = c.bounding_rect();
Rect r = static_cast<Rect>(c);
I do not understand what you are trying to say in the sentence quoted above, so kindly explain and elaborate.Quote:
Originally Posted by phantomotap
What I meant is that since a named conversion function forces the user of the type to explicitly request the conversion, any abuse of this conversion is the user's fault. With an implicit conversion function, any abuse of this conversion is both the user's fault and the type designer's (or implementor's) fault. The former is at fault for a mistake in using the type, and the latter is at fault for failing to disable the constructs that are not sensible.
Thank you for explaining
I also see this set off a discussion that would have made my head explode if I tried to understand most of it.:eek:Code:operator char*() {return ptr;}
I guess the point of this 'don't use automatic conversions'? I understood only the a = b - c issue, I don't know how widgets work, so I didn't understand it.
I've never touched any programming language before, so my total programming experience extends to about 5 months. ^^;
I'm reading "C++ without fear", if that indicates how new I am to all of this. So I don't really know how to make an explicit conversion function. I saw this in the "books" sections of cprogramming, so I'm reading those. I looked into other books, but I know so little I didn't know what to go with. So this is the first book I ended up getting.
I got the information I came for though, So thanks everyone! (And when I figure out how to write a function to take the place of operator char*(), I'll be sure to use it.)
The idea is that you create a function such as:
const char* get();
In your class instead of the implicit conversion operator:
operator const char* ();
This will eliminate the chance for these headaches.
Ahhh! Thank you, Elysia!:D I didn't know if making something like this required more work or not.
I appreciate the help, everyone! Thanks! :)
Also, non-const char* is bad for encapsulation. Basically, by returning a non-const char*, you implicitly give clients of your class leave to do with your internal string data whatever they want - not a good idea when the char* really belongs to the string object.