- assignment and implicit conversion - 4 Updates
- assignment and implicit conversion - 1 Update
- (int(*)(int)) ? - 3 Updates
- list of operating systems that can run C++? - 4 Updates
ram@zedat.fu-berlin.de (Stefan Ram): Mar 31 07:23AM I am trying to learn a little bit about assignment in C++. I have a vague memory that one can write some »constructor arguments« even after »return« or as a function argument, and then C++ will consider these values for implicit creation of an object of the required type. But I used to believe that this was not allowed in an assignment. Now, I tried this: #include <initializer_list> #include <iostream> #include <ostream> #include <string> using namespace ::std::literals; struct sigma { sigma( ::std::string const s ): x{ 1 }{} sigma( ::std::initializer_list<::std::string> const s ): x{ 2 }{} int x; }; int main() { sigma s{ "abc"s }; ::std::cout << s.x << '\n'; /* prints 2 */ s = "abc"s; ::std::cout << s.x << '\n'; /* prints 1 */ s ={ "abc"s }; ::std::cout << s.x << '\n'; /* prints 2 */ ::std::cout << "done.\n"s; } So it seems that one now can write a »constructor argument« for the RHS of the assignment and then C++ will do an implicit creation of a temporary with those expression as »constructor arguments«. Even with initializer lists! Or maybe this was always possible and I just did not know? Did I use the right words to describe what is happening? And since when is this allowed? (This is actually the central question of this post! I have a vague memory that initializer_lists where not always allowed in the RHS of an assignment.) So, one can use »constructor arguments« for a creation of an object in these places that I am aware of: - of course in a variable declaration - in a function-style cast - and I believe also in a static_cast - in a condition (e.g., "if( int x = ... )", 6.4p1) - in the RHS of an assignment (as being described above) - after a »return« - as an argument value - as an argument of emplace_back (but this might be just a special case of the preceding case) - Did I miss any cases? Are there any differences between these cases (in the sense that some types of constructions are only possible with some of these cases but not with others)? The common property of all these cases seems to be that the context gives an information about an »expected type«. |
ram@zedat.fu-berlin.de (Stefan Ram): Mar 31 06:44PM >I am trying to learn a little bit about assignment in C++. Now, a followup. The program was compiled and executed with GCC 5.1.1 and »-std=c++17«. In detail, the options were: -mwindows -msse2 -march=native -Ofast -O3 -std=c++17 -pedantic -pedantic-errors -Werror=narrowing -Wall -W -Wconversion -Wextra -Weffc++ -Wno-parentheses -Wno-unused-parameter -Wno-unused-variable -pthread #include <initializer_list> #include <iostream> #include <ostream> #include <string> #include <vector> using namespace ::std::literals; struct sigma { sigma( ::std::string const s ): x{ 1 }{} sigma( ::std::initializer_list<::std::string> const s ): x{ 2 }{} operator bool(){ return false; } int x; }; sigma f( sigma x ){ return { "a"s, "b"s }; } void try_out_sigma() { sigma s{ "abc"s }; ::std::cout << s.x << '\n'; s = "abc"s; ::std::cout << s.x << '\n'; s ={ "abc"s }; ::std::cout << s.x << '\n'; s ={ "a"s, "b"s }; ::std::cout << s.x << '\n'; f( { "a"s, "b"s } ); sigma t = sigma{ "a"s, "b"s }; ::std::cout << t.x << '\n'; /* sigma u = static_cast< sigma >( { "a"s, "b"s }); *//* No! */ sigma u = static_cast< sigma >( "a"s ); /* No! */ ::std::vector<sigma> v; v.emplace_back( "a"s ); /* v.emplace_back( { "a"s, "b"s } ); *//* No! Why? */ if( s ){} if( sigma{ "a"s, "b"s } ){} if( sigma t = "abc"s ){} if( sigma t{ "a"s, "b"s } ){} ::std::cout << "done.\n"s; } struct eta /* = explicit sigma */ { explicit eta( ::std::string const s ): x{ 1 }{} explicit eta( ::std::initializer_list<::std::string> const s ): x{ 2 }{} explicit operator bool(){ return false; } int x; }; void f( eta x ){ return; /* return { "a"s, "b"s }; */ /* No, explict! */ } void try_out_eta() { eta s{ "abc"s }; ::std::cout << s.x << '\n'; /* still ok */ /* s = "abc"s; ::std::cout << s.x << '\n'; */ /* No, explict! */ /* s ={ "abc"s }; ::std::cout << s.x << '\n'; */ /* No, explict! */ /* s ={ "a"s, "b"s }; ::std::cout << s.x << '\n'; */ /* No, explict! */ /* f( { "a"s, "b"s } ); */ /* No, explict! */ eta t = eta{ "a"s, "b"s }; ::std::cout << t.x << '\n'; /* still ok */ eta u = static_cast< eta >( "a"s ); /* still ok */ ::std::cout << u.x << '\n'; ::std::vector<eta> v; v.emplace_back( "a"s ); /* still ok */ if( s ){} /* still ok! Why? */ if( eta{ "a"s, "b"s } ){} /* if( eta t = "abc"s ){} *//* No, explict! */ if( eta t{ "a"s, "b"s } ){} /* still ok */ ::std::cout << "done.\n"s; } int main() { try_out_sigma(); try_out_eta(); } I have marked what I did not understand immediately with »Why?«. I observed that with GCC 5.1.1 and »-std=c++17«, I can write »if( s )« even though operator bool is explicit in »eta«. I remember that folks told me here that I cannot write »if( ::std::cin )« anymore, because something was »explicit«. Then why can I write »if( s )« above, when s is of type »eta« with an explicit operator bool()? I also tried »-Wno-unused-but-set-variable« to suppress »[Warning] variable 'u' set but not used [-Wunused-but-set-variable]«, but the warning still appears. |
ram@zedat.fu-berlin.de (Stefan Ram): Mar 31 09:54PM >And since when is this allowed? (This is actually the central >question of this post! I have a vague memory that initializer_lists >where not always allowed in the RHS of an assignment.) Seems to be C++14. |
ram@zedat.fu-berlin.de (Stefan Ram): Mar 31 11:21PM >>»if( s )« even though operator bool is explicit in »eta«. >`explicit` operator `bool` is implicitly invoked for an expression >that's used where the syntax requires a (C++ grammar) /condition/. Thank you! I confused this. I now see that #include <iostream> #include <ostream> int main() { if( ::std::cin ); int i; if( ::std::cin >> i ); } is allowed too. Somehow, I remembered falsely that this was now forbidden, but it is not. What now is forbidden instead is #include <iostream> #include <ostream> int main() { bool ok; if( ok = ::std::cin ); int i; if( ok = ::std::cin >> i ); } . >I prefer the named operation explicitly invoked, rather than the >implicitly invoked conversion. I was satisfied with if( ok = ::std::cin >> i )... which used to be possible. Now, I am using the following as an example in my C++ course. To give you some context, I quote the full program. #include <iostream> #include <ostream> #include <istream> #include <limits> int main() { double x; bool ok; do { ::std::cout << "Number? "; if( ok = static_cast< bool >( ::std::cin >> x ))::std::cout << x << '\n'; else { ::std::cout << "?REDO FROM START\n"; ::std::cin.clear(); ::std::cin.ignore ( ::std::numeric_limits< ::std::streamsize >::max(), '\n' ); }} while( !ok ); } One can see why I want the variable »ok«. I want it for the control of the do-while loop. I do not see the advantage of having to write if( ok = static_cast< bool >( ::std::cin >> x )) instead of if( ok = ::std::cin >> i ) . Ok, may be if( ok = bool( ::std::cin >> x )) would be less obtrusive, but isn't this bad style, because it does not contain the precise kind of cast? (After all, we were told not to use the C-style cast for this reason.) And what is not possible is if( ok = bool{ ::std::cin >> x }) because the braces there do not allow explicit conversions. |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 01 12:49AM +0200 On 31.03.2016 20:44, Stefan Ram wrote: > I observed that with GCC 5.1.1 and »-std=c++17«, I can write > »if( s )« even though operator bool is explicit in »eta«. `explicit` operator `bool` is implicitly invoked for an expression that's used where the syntax requires a (C++ grammar) /condition/. So, it's not perfect, but it's backward-compatible. If you really want a conversion to `bool` that can only be explicitly invoked, then the easiest is to use a named operation, e.g. `is_good`. Alternatively, one can use a Rube Goldberg scheme with `operator Private_member_ptr`, which doesn't convert to `void*`, so doesn't foul up overload resolution in general, but which does convert to `bool`. <code> #include <iostream> using namespace std; class S { private: enum Private {}; using Private_memptr = void(S::*)(Private); void True( Private ) {} public: auto is_good() const -> bool { return true; } operator Private_memptr() const { return (is_good()? &S::True : nullptr); } }; void foo( void const* ) { cout << "foo(ptr)" << endl; } void foo( ... ) { cout << "foo(...)" << endl; } auto main() -> int { S const o; foo( o ); // Invokes "foo(...)". if( o ) { cout << "Condition worked!" << endl; } bool const b = o; // Converts even if this isn't a "condition". (void) b; #ifdef GAH int const x = o; // !Doesn't convert. (void) x;
Subscribe to:
Post Comments (Atom)
|
No comments:
Post a Comment