|
|||
|
the motivation example is:
#include<string> #include<iostream> using namespace std; class S { public: operator string(){return " ";} }; int main() { std::cout<<S(); // error! but should it be? return 0; } true,there exists a quite simple and obvious alternative, that is, change 'S()' to 'string(S())' or '(string)S()'. also,this has no essential effect on code correctness, semantic ,whatever. But can anyone promise that nothing harmful would be caused by this inconvenience? For example, assume someone who write down such code and surely expects it works,but it doesn't,and the error message is quite puzzling,which basically says that "no viable function(s) found,the candidates are ....",but the candidate functions it lists out doesn't contain the one that takes a right-hand operator of type std::basic_string<...> const&, because it has been kicked out of the candidate set because of type deduction failure. And there's a little consideration as to code elegance ... On the other hand, loosen the type deduction rule a little bit seems not hurting the type system or language complexity. 14.8.2.1/3 lists out the exceptions. We can add another one(or modify the last bullet): if P is a class and P has the form template-id, normal conversion that is allowed in any other cases are allowed here, if there exists more than one conversion paths(possibility) that lead to different deduced A,type deduction fails[example: template<typename T> struct X { X(int); }; template<typename T> void f(X<T>); int main() { f(0); // 0 can be converted to X<T> whatever T is,in other words,there exists infinitude path, so type deduction fails of cause. } My question is, why not allow this, if its because of language complexity related consideration, please anyone tell me the rationale, thanks in advance;-) [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|
||||
|
||||
|
|
|
|||
|
pongba@gmail.com wrote:
> the motivation example is: > > #include<string> > #include<iostream> > using namespace std; > class S > { > public: > operator string(){return " ";} > }; > > int main() > { > std::cout<<S(); // error! but should it be? > return 0; > } > > true,there exists a quite simple and obvious alternative, that is, > change 'S()' to 'string(S())' or '(string)S()'. It is not at all obvious that simply because an object has a conversion function, that that conversion function is the one to invoke to output an object of that class to a stream. It seems to me that if a class can be streamed at all, that its output would be more elaborate than a single std::string. But only the programmer knows for sure how std::cout << S() should be handled. So rather than have the compiler guess, the program should specify the intended behavior and do so - not by an explicit type conversion as the example shows - but by an explicit type overload: ostream& operator<<(ostream& stream, const S& s) { stream << (string) s; // or whatever ... return stream; } Once this routine has been written, the question of implicit versus explicit type conversions becomes moot. > also,this has no essential effect on code correctness, semantic > ,whatever. But can anyone promise that nothing harmful would be caused > by this inconvenience? If the type conversion does harm, this proposal will do nothing to alleviate that harm. The type conversion would still take place, only its invocation could be implicit in addition to the explicit conversion supported today. And in fact, many would find the implicit type conversion more harmful, since its invocation is far less apparent in the source code. > For example, assume someone who write down such code and surely expects > it works,but it doesn't,and the error message is quite puzzling,which > basically says that "no viable function(s) found,the candidates are > ...",but the candidate functions it lists out doesn't contain the one > that takes a right-hand operator of type std::basic_string<...> const&, > because it has been kicked out of the candidate set because of type > deduction failure. > > And there's a little consideration as to code elegance ... > > On the other hand, loosen the type deduction rule a little bit seems > not hurting the type system or language complexity. > > 14.8.2.1/3 lists out the exceptions. We can add another one(or modify > the last bullet): > > if P is a class and P has the form template-id, normal conversion that > is allowed in any other cases are allowed here, if there exists more > than one conversion paths(possibility) that lead to different deduced > A,type deduction fails[example: > > template<typename T> > struct X > { > X(int); > }; > template<typename T> > void f(X<T>); > > int main() > { > f(0); // 0 can be converted to X<T> whatever T is,in other > words,there exists infinitude path, so type deduction fails of cause. > } > > My question is, why not allow this, if its because of language > complexity related consideration, please anyone tell me the rationale, > thanks in advance;-) You may wish to take up this suggestion with the readers of comp.std.c++. But given that implicit conversions are not well regarded in general, I would not expect that a proposal to extend their scope of operation would be enthusiastically embraced. But there is no harm in asking. The core problem with implicit conversions is that it lets the compiler write code. Unfortunately, the compiler isn't very good at writing software, or intuiting what the programmer intends to happen in a particular situation; therefore oftentimes the code that the compiler supplies (in the form of implicit convesions) is neither helpful nor even expected. Greg [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
> class S
> { > public: > operator string(){return " ";} > }; > > int main() > { > std::cout<<S(); // error! but should it be? > return 0; > } I'm not sure you're doing what you think you are. std::cout << S() is calling the class's constructor, which doesn't return a string (it returns an object of type "S"). I don't know of any operator string(), so I assumed you were thinking std::string operator()() { return std::string(" ");} Which can be used after you've constructed an object: int main() { S my_obj(); std::cout << my_obj(); } But I'm not sure. If you were trying to write a conversion to string, that may explain why a cast to string would get rid of your error. OTOH, the Correct Way was already suggested, define an operator<< that returns a std: stream.[ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
In article <1130371788.315662.246730@g14g2000cwa.googlegroups .com>,
mlybbert <mlybbert@users.sourceforge.net> writes >> class S >> { >> public: >> operator string(){return " ";} >> }; >> >> int main() >> { >> std::cout<<S(); // error! but should it be? >> return 0; >> } > >I'm not sure you're doing what you think you are. std::cout << S() is >calling the class's constructor, which doesn't return a string (it >returns an object of type "S"). I don't know of any operator string(), >so I assumed you were thinking Then it is time to do some learning. operator string() is the syntax C++ uses to declare a member function that provides a type conversion from the type being defined to the type specified. So in this case it provides a conversion from an instance of S to a string value. The problem, I think, is that the compiler does not know of a type called string (the writer probably meant std::string. -- Francis Glassborow ACCU Author of 'You Can Do It!' see http://www.spellen.org/youcandoit For project ideas and contributions: http://www.spellen.org/youcandoit/projects [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
mlybbert wrote:
> int main() > { S my_obj(); > std::cout << my_obj(); > } Do you realize that my_obj is a function, taking no parameters and returning an S object? And the next line calls that function? If you realized that, it wasn't obvious... you show no definition of my_obj. [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
Francis Glassborow wrote:
> In article <1130371788.315662.246730@g14g2000cwa.googlegroups .com>, > mlybbert <mlybbert@users.sourceforge.net> writes > >> class S > >> { > >> public: > >> operator string(){return " ";} > >> }; > >> int main() > >> { > >> std::cout<<S(); // error! but should it be? > >> return 0; > >> } > >I'm not sure you're doing what you think you are. std::cout > ><< S() is calling the class's constructor, which doesn't > >return a string (it returns an object of type "S"). I don't > >know of any operator string(), so I assumed you were thinking > Then it is time to do some learning. operator string() is the > syntax C++ uses to declare a member function that provides a > type conversion from the type being defined to the type > specified. So in this case it provides a conversion from an > instance of S to a string value. > The problem, I think, is that the compiler does not know of a > type called string (the writer probably meant std::string. The original code had a "using namespace std;" immediately after the includes. It's quite clear which string is meant. The original poster pointed out the actual problem quite exactly (and showed a very good knowledge of C++ in doing so -- it's far from evident, and had he not pointed it out, I'm not sure I would have spotted it). The std: perator<< function which isneeded is a template. And the type conversion in question doesn't occur during type deduction, so the appropriate operator<< function never gets instantiated, never makes it into the overload set, and so, of course, can't be chosen by overload resolution. Note that this doesn't work with an operator char const* either; the problem is the same. And that is does work with operator char const* in the classical streams. This is something that the committee broke when they made iostream a template. A sort of a weak justification would be that it is bad code anyway, that you shouldn't use an implicit conversion for this sort of thing. -- James Kanze GABI Software Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
pongba@gmail.com wrote:
> the motivation example is: > > #include<string> > #include<iostream> > using namespace std; > class S > { > public: > operator string(){return " ";} > }; > > int main() > { > std::cout<<S(); // error! but should it be? > return 0; > } > > true,there exists a quite simple and obvious alternative, that is, > change 'S()' to 'string(S())' or '(string)S()'. > > also,this has no essential effect on code correctness, semantic > ,whatever. But can anyone promise that nothing harmful would be caused > by this inconvenience? > > For example, assume someone who write down such code and surely expects > it works,but it doesn't,and the error message is quite puzzling,which > basically says that "no viable function(s) found,the candidates are > ....",but the candidate functions it lists out doesn't contain the one > that takes a right-hand operator of type std::basic_string<...> const&, > because it has been kicked out of the candidate set because of type > deduction failure. > > And there's a little consideration as to code elegance ... > > On the other hand, loosen the type deduction rule a little bit seems > not hurting the type system or language complexity. > > 14.8.2.1/3 lists out the exceptions. We can add another one(or modify > the last bullet): > > if P is a class and P has the form template-id, normal conversion that > is allowed in any other cases are allowed here, if there exists more > than one conversion paths(possibility) that lead to different deduced > A,type deduction fails[example: > > template<typename T> > struct X > { > X(int); > }; > template<typename T> > void f(X<T>); > > int main() > { > f(0); // 0 can be converted to X<T> whatever T is,in other > words,there exists infinitude path, so type deduction fails of cause. > } > > My question is, why not allow this, if its because of language > complexity related consideration, please anyone tell me the rationale, > thanks in advance;-) If you change in "motivation example" operator string() to operator int() you will achieve desired behavior. It's the matter of STL implementation. If you take a look at operator << for the string you will see: template<class _Elem, class _Traits, class _Alloc> inline basic_ostream<_Elem, _Traits>& __cdecl operator<<( basic_ostream<_Elem, _Traits>& _Ostr, const basic_string<_Elem, _Traits, _Alloc>& _Str) { .... Thus compiler needs to make two translations: one - to construct std::string from class S and second - to instantiate operator << for the string. It's forbidden by the standard. You can write your own operator << for the string, just delegating call to template: #include <string> #include <iostream> class A { public: operator std::string () { return "0123456789"; } }; std: stream& operator << ( std: stream& stream, const std::string&string ) { return std: perator << ( stream, string );} int main() { std::cout << A() << std::endl; return 0; } Alexander Kozlov. [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
Sorry, Allan, maybe my original code examples did not make it clear
they were meant to be used (1) together, and (2) in conjunction with the original post: #include <string> #include <iostream> class S { public: std::string operator()() { return std::string(" ");} }; int main() { S my_obj(); std::cout << my_obj(); return 0; } In which case, my_obj is an instance of class S, and all instances of class S have an operator() that takes no parameters, and returns a std::string consisting of one space. The technique is called a functor or function-like object. But, thanks to Francis Glassborow, I learned the original post was supposed to do what the original poster expected it to. [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
mlybbert wrote:
> Sorry, Allan, maybe my original code examples did not make it > clear they were meant to be used (1) together, and (2) in > conjunction with the original post: I think Allan knew that. > #include <string> > #include <iostream> > class S > { > public: > std::string operator()() { return std::string(" ");} > }; > int main() > { S my_obj(); > std::cout << my_obj(); > return 0; > } > In which case, my_obj is an instance of class S, No it's not. That's Allan's point. As written, my_obj is an external function taking no parameters, and returning an S. In the following line, you call the function. I don't know what compiler you tried this with. Logically, you should get exactly the same error as the original poster, so the code won't compile. If you insert a cast manually: std::cout << static_cast< std::string >( my_obj() ) ; it of course compiles, but you should get an error from the linker about a missing definition for my_obj. If you're seeing anything else, you're compiler isn't conform. > and all instances of class S have an operator() that takes no > parameters, and returns a std::string consisting of one space. > The technique is called a functor or function-like object. > But, thanks to Francis Glassborow, I learned the original post > was supposed to do what the original poster expected it to. And thanks to Allan's posting, you've learned about C++'s most aggravating parse problem:-). -- James Kanze mailto: james.kanze@free.fr Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34 [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
syntetic@mail.ru wrote:
> pongba@gmail.com wrote: > > the motivation example is: > > #include<string> > > #include<iostream> > > using namespace std; > > class S > > { > > public: > > operator string(){return " ";} > > }; > > int main() > > { > > std::cout<<S(); // error! but should it be? > > return 0; > > } > > true,there exists a quite simple and obvious alternative, > > that is, change 'S()' to 'string(S())' or '(string)S()'. > > also,this has no essential effect on code correctness, > > semantic, whatever. But can anyone promise that nothing > > harmful would be caused by this inconvenience? > > For example, assume someone who write down such code and > > surely expects it works,but it doesn't,and the error message > > is quite puzzling,which basically says that "no viable > > function(s) found,the candidates are ....",but the candidate > > functions it lists out doesn't contain the one that takes a > > right-hand operator of type std::basic_string<...> const&, > > because it has been kicked out of the candidate set because > > of type deduction failure. > > And there's a little consideration as to code elegance ... > > On the other hand, loosen the type deduction rule a little > > bit seems not hurting the type system or language > > complexity. > > 14.8.2.1/3 lists out the exceptions. We can add another > > one(or modify the last bullet): > > if P is a class and P has the form template-id, normal > > conversion that is allowed in any other cases are allowed > > here, if there exists more than one conversion > > paths(possibility) that lead to different deduced A,type > > deduction fails[example: > > template<typename T> > > struct X > > { > > X(int); > > }; > > template<typename T> > > void f(X<T>); > > int main() > > { > > f(0); // 0 can be converted to X<T> whatever T is,in other > > words,there exists infinitude path, so type deduction fails of cause. > > } > > My question is, why not allow this, if its because of > > language complexity related consideration, please anyone > > tell me the rationale, thanks in advance;-) > If you change in "motivation example" operator string() to > operator int() you will achieve desired behavior. That's true, but not at all for the reasons you say. <<int is a member function, not a global function. As such, it's declaration is instantiated when the class is instantiated, so the operator is available for overload resolution. > It's the matter of STL implementation. If you take a look at > operator << for the string you will see: > template<class _Elem, > class _Traits, > class _Alloc> inline > basic_ostream<_Elem, _Traits>& __cdecl operator<<( > basic_ostream<_Elem, _Traits>& _Ostr, > const basic_string<_Elem, _Traits, _Alloc>& _Str) > { > ... > Thus compiler needs to make two translations: What exactly do you mean by translations, here. There is exactly one conversion, in both his case and yours. > one - to construct std::string from class S and second - to > instantiate operator << for the string. It's not a question of two anything. String or int, there is one user defined conversion operator, which is allowed in function overloading. The problem is that user defined conversion operators are not taken into account during template type deduction; since op<< for string is a global template function, its declaration needs to be instantiated for it to be considered by overload resolution. The second parameter of the op<< string is a type which depends on the the template, so it is taken into account for type deduction. And since type deduction doesn't take any user defined conversions into account, the template doesn't get instantiated, and the function is not considered during overload resolution. > It's forbidden by the standard. You can write your own > operator << for the string, That sounds like a recepe for trouble. Anytime type deduction does instantiate the standard function, you end up with an ambiguity. > just delegating call to template: > #include <string> > #include <iostream> > class A { > public: > operator std::string () { return "0123456789"; } > }; > std: stream& operator << ( std: stream& stream, const std::string&> string ) { > return std: perator << ( stream, string );> } > int main() { > std::cout << A() << std::endl; > return 0; > } Yes, but now something simple like: std::string s( "abcd" ) ; std::cout << s ; fails. In this case, the problem is depending on implicite conversion functions. A better solution would have involved writing an operator<< for the class in question, so no conversion would be necessary. -- James Kanze GABI Software Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
/* As written, my_obj is an external function taking no parameters, and
returning an S. In the following line, you call the function. */ Alright, how would I create an object of type S, call it my_obj, and place it on the stack instead of the heap? Remember, the constructor for S doesn't take any parameters. Yes, I could have written "S* my_obj_on_the_heap = new S;" but I want it on the stack, so I don't have to delete anything manually. [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
To be honest, James, I have not tried compiling my example. I was
simply following the pattern of a funtion-like object. There is an example at http://www.research.att.com/~bs/bs_f...unction-object You'll also note that the same page has an example of a user defined conversion in the mode of "operator string," so I whould have known what the original post was about. [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
mlybbert wrote:
> /* As written, my_obj is an external function taking no > parameters, and returning an S. In the following line, you > call the function. */ > Alright, how would I create an object of type S, call it > my_obj, and place it on the stack instead of the heap? > Remember, the constructor for S doesn't take any parameters. S my_obj ; This is pretty much basic C++. Adding the parentheses is a classical beginner's mistake, and is generally covered fairly early in any C++ course, because the fact that you cannot add them (for historical reasons) IS somewhat counter-intuitive. -- James Kanze GABI Software Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Corrected: Proposal: Increasing type safety with a keyword | Ioannis Vranos | Newsgroup comp.lang.c | 9 | 04-01-2009 09:17 AM |
| Re: set with 2 databases | Ian Whitlock | Newsgroup comp.soft-sys.sas | 0 | 12-09-2005 05:18 PM |
| Re: Type I-IV Sum of squares with empty cells | baogong jiang | Newsgroup comp.soft-sys.sas | 0 | 05-19-2005 03:35 PM |
| Re: Type I-IV Sum of squares with empty cells | Robin High | Newsgroup comp.soft-sys.sas | 1 | 05-18-2005 03:56 AM |