- question wrt std::result_of - 6 Updates
- Copy and Direct Initialization - 2 Updates
- Why is the ranged for loop not working with the iterator defined the following way? - 3 Updates
- A good error case practice - 1 Update
- question wrt std::result_of - 3 Updates
ram@zedat.fu-berlin.de (Stefan Ram): Aug 22 12:44AM > cout << typeid( fn ) << endl; #include <iostream> #include <ostream> #include <typeinfo> #include <string> using namespace ::std::literals; struct entity { double entity{ 25 }; }; int main() { ::std::cout << typeid( 2 ).name() << '\n'; ::std::cout << typeid( int ).name() << '\n'; ::std::cout << typeid( 2.3 ).name() << '\n'; ::std::cout << typeid( double ).name() << '\n'; ::std::cout << typeid( "2.3"s ).name() << '\n'; ::std::cout << typeid( ::std::string ).name() << '\n'; ::std::cout << typeid( entity{} ).name() << '\n'; ::std::cout << typeid( entity ).name() << '\n'; } i i d d NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE 6entity 6entity /* for GCC C++ */ #include <cxxabi.h> #include <iostream> #include <ostream> #include <typeinfo> #include <string> using namespace ::std::literals; struct entity { double entity{ 25 }; }; const char* decode( const char * const typnam ) { static char buf[ 999 ]; size_t size = sizeof( buf ); int st; char const * const result = ::abi::__cxa_demangle( typnam, buf, &size, &st ); buf[ size - 1 ]= 0; return result; } int main() { ::std::cout << decode( typeid( 2 ).name() )<< '\n'; ::std::cout << decode( typeid( int ).name() )<< '\n'; ::std::cout << decode( typeid( 2.3 ).name() )<< '\n'; ::std::cout << decode( typeid( double ).name() )<< '\n'; ::std::cout << decode( typeid( "2.3"s ).name() )<< '\n'; ::std::cout << decode( typeid( ::std::string ).name() )<< '\n'; ::std::cout << decode( typeid( entity{} ).name() )<< '\n'; ::std::cout << decode( typeid( entity ).name() )<< '\n'; } int int double double std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > entity entity |
ram@zedat.fu-berlin.de (Stefan Ram): Aug 22 12:58AM >{ static char buf[ 999 ]; size_t size = sizeof( buf ); int st; > char const * const result = ::abi::__cxa_demangle( typnam, buf, &size, &st ); > buf[ size - 1 ]= 0; return result; } This implementation of »decode« still contains errors, but seems to work in the special case of the program given. To write a better »decode«, one case read the documentation of »::abi::__cxa_demangle« and just follow all the advice given there! |
ram@zedat.fu-berlin.de (Stefan Ram): Aug 22 12:18PM I would like to understand the difference between copy and direct initialization, that is, between T x = a; versus T x( a ); / T x{ a }. 1st: With direct initialization available, is there a reason anyone would ever want to use copy initialization when writing new code? Are there use cases where copy initialization is much better than direct initialization? 2nd: On a webpage, someone said that direct initialization is like a constructor call, possibly with conversions of the arguments used, while copy initialization will »construct a conversion sequence«. Does the word »sequence« hint at a possible fact that direct initialization is using /at most one/ conversion per argument while copy initialization might use /a sequence of/ several conversions to convert the right-hand side to the type of the left-hand side? 3rd: IIRC, direct initialization can implicitly use type conversions that where marked with »explicit«, while copy initialization does not. So this might be a use case for copy initialization: When one does not want to use explicit conversions? Are there other important differences between direct initialization and copy initialization that can decide which one to choose for reasons of good style or secure or efficient coding in cases where both would be possible? |
ram@zedat.fu-berlin.de (Stefan Ram): Aug 22 02:57PM >Objective is to illustrate the usage of iterators in ranged for loop. I have the following piece of code: I never implemented an iterator for a range-based for loop before. I just took the source code given and changed it until it worked. So there might still be severe errors, because I did not know what I was actually doing. struct string { char const * const text; int length; string( const char * const text ): text{ text }, length{ 0 } { char const * p = this->text; while( *p++ )++length; }}; struct string_iterator { char const * p; string_iterator( string const string ): p{ string.text } {}; string_iterator & operator ++(){ ++p; return *this;} string_iterator & operator +=( const int i ){ p += i; return *this; } bool operator ==( string_iterator const & other ){ return other.p == this->p; } bool operator !=( string_iterator const & other ){ return !( *this == other ); } char operator *(){ return *p; }}; string_iterator operator +( string_iterator result, int const number ) { result += number; return result; } string_iterator begin( string const & string ){ return string_iterator( string );} string_iterator end( string const & string ){ return string_iterator( string )+ string.length; } int main() { string string{ "hello, world!" }; ::std::cout << string.text << '\n'; for( string_iterator iter = begin( string ); iter != end( string ); ++iter ) ::std::cout << *iter; ::std::cout << '\n'; for( char const c : string )::std::cout << c; ::std::cout<< '\n'; } hello, world! hello, world! hello, world! |
ram@zedat.fu-berlin.de (Stefan Ram): Aug 22 03:03PM >string_iterator operator +( string_iterator result, int const number ) >{ result += number; return result; } Since this is a small function, but defined outside of a class specifier, it might well deserve an »inline«. (Functions declared within a class specifier are inline.) |
ram@zedat.fu-berlin.de (Stefan Ram): Aug 22 06:43PM >using /at most one/ conversion per argument while copy >initialization might use /a sequence of/ several conversions >to convert the right-hand side to the type of the left-hand side? Thanks for the answers! In the meantime, I tried the following code which shows exactly the opposite of the possibility given above: #include <iostream> struct alpha { alpha(){ ::std::cout << "alpha\n"; }}; struct beta { beta( alpha ){ ::std::cout << "beta( alpha )\n"; }}; struct gamma { gamma( beta ){ ::std::cout << "gamma( beta )\n"; }}; int main() { { beta b = alpha{}; /* gamma g = alpha{}; */ } { beta b{ alpha{} }; gamma g{ alpha{} }; }} alpha beta( alpha ) alpha beta( alpha ) alpha beta( alpha ) gamma( beta ) That is, the compiler used did /not/ use the sequence of two conversions in the case of /copy/ initialization. (This has been commented out above, because it gives an error message.) But it /did/ use the sequence in the case of /direct/ initialization. |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Aug 22 04:15PM +0200 On 22.08.2015 14:18, Stefan Ram wrote: > reason anyone would ever want to use copy initialization > when writing new code? Are there use cases where copy > initialization is much better than direct initialization? "=" was the original C initialization syntax. I find it more clear and easy to recognize when I see that "=". With C++03 there were some good reasons to use direct initialization here and there, in particular for non-copyable types like streams, but in C++11 and later they're typically movable. > 2nd: On a webpage, someone said that direct initialization > is like a constructor call, possibly with conversions of > the arguments used, No, the word "like" indicates some difference in the details, but it just is a constructor call, plain and simple. > using /at most one/ conversion per argument while copy > initialization might use /a sequence of/ several conversions > to convert the right-hand side to the type of the left-hand side? The sequence for copy initialization of a T object is (1) conversion to T, and (2) a copy or move constructor call of T. Where the latter can be optimized away, regardless of side-effects of those constructors (they must still be accessible though, so that the code can compile with a compiler that doesn't do that optimization). IIRC correctly the standard uses the word "elided", but that may be just a word we used here in the Usenet groups. > copy initialization does not. So this might be a use case > for copy initialization: When one does not want to use > explicit conversions? Yes, but I have not encountered any case where I'd want that. > can decide which one to choose for reasons of good style > or secure or efficient coding in cases where both would be > possible? Yes, even though one might argue that that's already covered by the clarity & easy-to-recognize reason, one might use copy initialization to avoid verbosity. long_silly_type_spec o1( foo<another_long_silly_type_spec>() ); auto o2 = foo<another_long_silly_type_spec>(); Or like wchar_t const* const s1( L"Bah!" ); auto const s2 = L"Bah!"; Of course, there are also cases where it is direct initialization that cuts down the verbosity. Cheers & hth., - Alf |
Victor Bazarov <v.bazarov@comcast.invalid>: Aug 22 02:19PM -0400 On 8/22/2015 8:18 AM, Stefan Ram wrote: > reason anyone would ever want to use copy initialization > when writing new code? Are there use cases where copy > initialization is much better than direct initialization? No, but there are cases you have no control over. For instance, function arguments are sometimes copy-initialized. Template code can be written T x = a;, and it will only be instantiated if you use it. > using /at most one/ conversion per argument while copy > initialization might use /a sequence of/ several conversions > to convert the right-hand side to the type of the left-hand side? The Standard says that there can be at most three conversions, IIRC. A standard conversion followed by user-defined one, followed by another standard conversion, but I don't remember all circumstances where those apply. > can decide which one to choose for reasons of good style > or secure or efficient coding in cases where both would be > possible? I am not sure it matters, really. However, I have seen code in which copy-construction was simply disabled (or made inaccessible), and it needs to be accessible in the scope in which T x = a; is used instead of T x{a}; V -- I do not respond to top-posted replies, please don't ask |
emakalam@gmail.com: Aug 22 07:20AM -0700 Objective is to illustrate the usage of iterators in ranged for loop. I have the following piece of code: #include <iostream> class str{ char *s; int c; public: str(char *x): s {x} {c = 0; while(*x++)c++;} struct iterator{ iterator(char* x) : c {x} {}; inline iterator& operator ++() {++c; return *this;} inline bool operator == (iterator x) {return x.c == this->c;} inline bool operator != (iterator x) {return x.c != this->c;} inline char operator *() {return *c;} char* c; }; iterator begin(){return iterator(s);} iterator end(){return iterator(s+c);} }; int main(){ str x {(char *)"hello world"}; for(str::iterator c : x) //this gives error*. See below std::cout << *c; std::cout<<std::endl; for (str::iterator c = x.begin(); c!=x.end();++c) //this works fine std::cout<<*c; std::cout<<std::endl; } I wonder why the normal for works but the ranged for does not. Can you kindly take your time and point out the error ? errors: MSVC: c.cpp(22): error C2440: 'initializing': cannot convert from 'char' to 'str::iterator'c.cpp(22): note: No constructor could take the source type, or constructor overload resolution was ambiguous GCC: c.cpp:22:31: error: invalid conversion from 'char' to 'char*' [-fpermissive] |
Bo Persson <bop@gmb.dk>: Aug 22 05:03PM +0200 > errors: > MSVC: c.cpp(22): error C2440: 'initializing': cannot convert from 'char' to 'str::iterator'c.cpp(22): note: No constructor could take the source type, or constructor overload resolution was ambiguous > GCC: c.cpp:22:31: error: invalid conversion from 'char' to 'char*' [-fpermissive] The range for loop will not only iterate over the range, but also dereference the iterator for you. The message mentions that it has a char and not an iterator. Bo Persson |
"Öö Tiib" <ootiib@hot.ee>: Aug 22 08:53AM -0700 > str x {(char *)"hello world"}; > for(str::iterator c : x) //this gives error*. See below > std::cout << *c; The error diagnostic states quite clearly that you attempt to use 'str::iterator' where 'char' is available but it can't convert 'char' to 'str::iterator'. Most likely you wanted that: for ( char c : x ) std::cout << c; Read the description of features more carefully and also look at the examples in book. When compiler complains about what you do but you think that you did all correctly then it indicates that you misunderstood how a feature works. |
Paavo Helde <myfirstname@osa.pri.ee>: Aug 22 02:13AM -0500 >> ...So this shows that books and the web are fine, but to really learn >> what matters, one Must Read The Usenet! > Thanks, interesting things In this case, the knowledge comes from the C++ standard, and the standard (at least the final draft) is available in the web: 15.5.1/2: "In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called." This also shows that Usenet was not really precise when calling the behavior "unspecified" as this is a bit different from "implementation- defined". Cheers Paavo |
Doug Mika <dougmmika@gmail.com>: Aug 21 05:12PM -0700 On Friday, August 21, 2015 at 5:48:35 PM UTC-5, Alf P. Steinbach wrote: > > } > Cheers & hth., > - Alf My function fn was: int fn(int a) {return a;} // function and if I could cout the decltype(fn), would it be something as follows: int*(int)? Or is the function type merely it's return type? |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Aug 22 02:23AM +0200 On 22.08.2015 02:12, Doug Mika wrote: > int fn(int a) {return a;} // function > and if I could cout the decltype(fn), would it be something as follows: > int*(int)? Just `int(int)`. With the * (which would be written `int(*)(int)`) you'd have a function pointer type. And yes you can display a representation of the type. Just include the `<typeinfo>` header and do cout << typeid( fn ) << endl; With Visual C++ you get a readable representation by default. With g++ you get a pretty unreadable compact result, but that can be fixed via some compiler-specific functionality (I'd have to google it again, sorry). With clang I'm not sure, but it's probably just like g++, because clang was designed as a drop-in replacement for g++. Correspondingly, the Intel compiler, IIRC designed as a drop in replacement for Visual C++, is probably just like Visual C++. Summing up, the result and how to fix-if-necessary depends on the compiler. > Or is the function type merely it's return type? No, the type is the full type, namely result and argument types. The /signature/ is just the arguments, that is, the signature is the function type without the result type. The signature is a useful concept because overload resolution in C++ ignores the result type. Cheers & hth., - Alf |
02xiaoma <02xiaoma@gmail.com>: Aug 21 07:39PM -0700 在 2015年8月22日星期六 UTC+8上午3:12:15,Doug Mika写道: > std::cout<<b<<std::endl; > return 0; > } you can write like this : std::result_of<decltype(fn)*(int)>::type b; or you can write like this: int(*func)(int); func = fn; std::result_of<decltype(func)(int)>::type b; from MSDN: The template class defines its member type as a synonym for the return type of a function call described by its template argument Ty. The template argument must be of the form Fty(T1, T2, ..., TN), where Fty is a callable type. The template determines the return type according to the first of the following rules that applies: if Fty is a pointer to function type R(*)(U1, U2, ..., UN) the return type is R; if Fty is a reference to function type R(&)(U1, U2, ..., UN) the return type is R; ... if you really want to know what happens, you can go to look at the what is in the STL. be happy |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment