- Is template metaprogramming allowed by the standard? - 6 Updates
- shared_ptr id - 10 Updates
- the smaller prog C++ - 1 Update
David Harmon <source@netcom.com>: Apr 11 10:28PM -0700 On Sat, 11 Apr 2015 18:05:41 +0000 (UTC) in comp.lang.c++, Juha Nieminen <nospam@thanks.invalid> wrote, >Btw, define "template metaprogramming". Writing your own c++ templates, as distinguished from using templates someone else has written or from the standard library. |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Apr 12 06:16AM On Sat, 2015-04-11, Paavo Helde wrote: >> template <class InputIterator> >> vector(InputIterator, InputIterator) >> the former is a decent match, and the latter is worse It's not worse, of course -- it's a perfect match, with InputIterator = int. Sorry for confusing things. >> (and wouldn't compile anyway if it was chosen). > 10 and 20 are of type int, which is different from size_type and const > size_t&. A little experiment shows this is not so trivial: [snip] > second constructor to fail at the substitution stage (SFINAE) for integer > types so that the first constructor gets selected. And yes, switching > overloads on and off at compile time seems pretty TMP for me. Whatever it is, I now see it's worth understanding. /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
Paavo Helde <myfirstname@osa.pri.ee>: Apr 12 02:57AM -0500 David Harmon <source@netcom.com> wrote in news:D8idnXi_a7LFn7fInZ2dnUU7- >>Btw, define "template metaprogramming". > Writing your own c++ templates, as distinguished from using templates > someone else has written or from the standard library. This might be a useful definition, but not exactly what the OP was interested in. He asked: "Is template metaprogramming a serious programming technique, used in real-life code?" and "Is template metaprogramming allowed by the standard?" These are actually a bit orthogonal questions, but answer to both is yes. The standard library and many other template libraries (including many Boost libraries, for example) are pretty serious and used very heavily in real world. And yes, this is all backed up by the standard. As always, any given C++ compilers might lack or misbehave with some (typically newer or more exotic) template features, but this is no different from non-template features. Cheers Paavo |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Apr 12 09:00AM On Sun, 2015-04-12, David Harmon wrote: >>Btw, define "template metaprogramming". > Writing your own c++ templates, as distinguished from using templates > someone else has written or from the standard library. That's not how most people use the term. Stroustrup has a rather long discussion about the difference between generic programming and template metaprogramming: The C++ Programming Language, 4th ed, section 28.1. Sorry, I'm too lazy to quote or summarize it. /Exactly/ where the border between the two goes is, for me personally, not that interesting. I hope there isn't a trend to spread fear and doubt about generic programming, by associating it with template metaprogramming. The former is obviously useful to almost everyone, and nothing to be afraid of. The latter is ... well, I haven't quite grasped it in practice yet. /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Apr 12 05:08PM +0100 On Fri, 10 Apr 2015 15:22:18 -0700 (PDT) > metaprogramming merely a curiosity, an unexpected side effect of > adding templates to language definition and everything about it is > either undefined or implementation defined? Compile time programming using templates is entirely standardized, in the sense that templates are standardized. It is sometimes said that TMP is an unexpected side effect of creating a template system originally intended for "cookie cutting", but it is now well used both within the standard library and by other libraries. std::tuple for example is implemented using TMP with recursive inheritance. C++11/14 also provides a complete type trait library providing (amongst other things) compile time predicates and type transformations. One implied question that you have asked is the extent to which compilers correctly implement templates in conformity with the standard. In my experience, gcc >= 4.8, and clang >= 3.4, are nearly completely conformant with respect to templates. Earlier versions of gcc correctly implement type traits (I believe from around gcc-4.3 or 4.4 onwards - it is a long time since I used those compilers) but have a number of infelicities at the edges. Recent versions of visual studio are reputed to be more or less completely compliant. If you are writing an average program, you may never need to know about or understand TMP. The libraries used by the program will do the work for you. If you are writing a library for C++11 or C++14 you will probably at least use the type traits library and quite probably a great deal more. To take a simple example, if you are forwarding arguments using C++11/14 "universal"/"collapsible" references, you may well find yourself needing to use std::remove_reference to convert a deduced reference type where an lvalue is passed to the underlying type when instantiating a template. This is trivial to do but would generally be classed as compile time meta programming. Chris |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Apr 12 11:26PM On Sun, 2015-04-12, Chris Vine wrote: ... > TMP is an unexpected side effect of creating a template system > originally intended for "cookie cutting", but it is now well used both > within the standard library and by other libraries. And Stroustrup's angle on that is at http://www.stroustrup.com/bs_faq.html#understand /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
"Norman J. Goldstein" <normvcr@telus.net>: Apr 12 12:57AM -0700 I would find it helpful for a shared_ptr to have an id() method, so that two shared_ptr's manage the same object only if and only if they have the same id's. If the managed object is not NULL, then the address of the object can work as an id. Obviously, this does not work if the object is NULL. An easy way to implement id(), for example, would be to return the address of the location that stores the link count for the shared_ptr. Any thoughts on this? |
Marcel Mueller <news.5.maazl@spamgourmet.org>: Apr 12 10:19AM +0200 On 12.04.15 09.57, Norman J. Goldstein wrote: > the same id's. If the managed object is not NULL, then the address of > the object can work as an id. Obviously, this does not work if the > object is NULL. Why not? If a pointer does not point to an object then there is no definition of "the same object". And it is common practice and sometimes very useful that reference-equals comparisons return true if both operands point to the same object /or/ both are NULL. > return the address of the location that stores the link count for the > shared_ptr. > Any thoughts on this? Not recommended from my point of view. #1 It is already possible to write x.get() == y.get() and the intention of this comparison is obvious. #2 Wrapping this by an id() function would allow to compare pointers of incompatible type without an error. #3 The data type of the id() cannot be safely int when sizeof(int) is less than sizeof(X*). Marcel |
Paavo Helde <myfirstname@osa.pri.ee>: Apr 12 06:57AM -0500 "Norman J. Goldstein" <normvcr@telus.net> wrote in news:mgd8gt$pil$1 > object is NULL. An easy way to implement id(), for example, would be to > return the address of the location that stores the link count for the > shared_ptr. This would not work if the link count is embedded in the linked object or added to it via std::make_shared(). Also, conceptually I do not get why such a feature would be useful. A smartpointer becomes NULL only if I assign NULL to it. Why should it then remember to which object it pointed earlier? If I wanted to remember that, I would not have assigned NULL to it in the first place. Cheers Paavo |
"Öö Tiib" <ootiib@hot.ee>: Apr 12 06:02AM -0700 On Sunday, 12 April 2015 11:20:06 UTC+3, Marcel Mueller wrote: > And it is common practice and sometimes very useful that > reference-equals comparisons return true if both operands point to the > same object /or/ both are NULL. Yes, that is common practice. > of this comparison is obvious. > #2 Wrapping this by an id() function would allow to compare pointers of > incompatible type without an error. It may be desirable to compare smart pointers of incompatible type to find out if they do (or do not) alias to same most derived object. The expression above does not compile on case where 'x' is 'std::shared_ptr<base_1>' and 'y' is 'std::shared_ptr<base_2>' and 'base_1' and 'base_2' are unrelated base classes. The 'x' and 'y' may actually use same reference counter if there is multiple inheritance. To resolve the issue we can write: dynamic_cast<void*>(x.get()) == dynamic_cast<void*>(y.get()) However that looks ugly (can be mitigated with inline function) requires RTTI and is likely less efficient than to compare addresses of reference counter if any. Both efficiency difference and the ugliness grow when at least one is 'weak_ptr'. > #3 The data type of the id() cannot be safely int when sizeof(int) is > less than sizeof(X*). Why it must be 'int'? To me it seems that OP clearly wrote that his simplest implementation returns address of reference count. Reference count is 'long' by C++ standard, Address to it is 'long*'. So 'id()' can return 'void const*' or 'intptr_t'. |
"Öö Tiib" <ootiib@hot.ee>: Apr 12 06:29AM -0700 On Sunday, 12 April 2015 14:57:31 UTC+3, Paavo Helde wrote: > > shared_ptr. > This would not work if the link count is embedded in the linked object or > added to it via std::make_shared(). Why it won't work? The reference count of 'shared_ptr' (and 'weak_ptr') must be 'long int' regardless of where it is stored. Its address can't move around in memory during life-time of referenced object. > smartpointer becomes NULL only if I assign NULL to it. Why should it then > remember to which object it pointed earlier? If I wanted to remember that, > I would not have assigned NULL to it in the first place. Maybe what he wants is something achievable with 'std::shared_ptr::owner_before' or 'std::shared_ptr::owner_less'. He did not describe it too well. |
"Norman J. Goldstein" <normvcr@telus.net>: Apr 12 10:03AM -0700 Thanks for all the responses. I will address all the comments and clarify, further. On Sunday, 12 April 2015 11:20:06 UTC+3, Marcel Mueller wrote: > And it is common practice and sometimes very useful that > reference-equals comparisons return true if both operands point to the > same object /or/ both are NULL. *> Yes, that is common practice. In the case of shared_ptr's, it is wrong, in my situation, to take a NULL pointer as a shared reference. I am interested only in the relationship reflected by the use_count() . A NULL pointer has an address, say, of 0, so this cannot be used to determine whether two shared_ptr's are managing the same object. If one of the two shared_ptr's does reset( new T ), then the two shared_ptr's will both be managing a bona fide same object. So, even if the managed object is NULL, the relationship between the two shared_ptr's is maintained. The use_count() is (at least) two for the two shared_ptr's, even if they are sharing only NULL. On 04/12/2015 06:29 AM, Öö Tiib wrote: >> smartpointer becomes NULL only if I assign NULL to it. Why should it then >> remember to which object it pointed earlier? If I wanted to remember that, >> I would not have assigned NULL to it in the first place. As pointed out, above, shared_ptr's do remember the relationship, even if they are assigned NULL. The point I am making is that I would like to be able to query that relationship, even if the pointer value is NULL. > Maybe what he wants is something achievable with > 'std::shared_ptr::owner_before' or 'std::shared_ptr::owner_less'. He did > not describe it too well. I'm sorry, I don't understand these suggestions. The reason that I want the id() feature, is so that I can save shared_ptr's to disk, and when they get restored to RAM, they maintain the same relationship. Currently, when the shared_ptr's are NULL, I cannot do this. During the running of the program, one of the shared_ptr's might do a reset( new T ), and all the (intended) shared_ptr's must see the change. |
"Öö Tiib" <ootiib@hot.ee>: Apr 12 12:18PM -0700 On Sunday, 12 April 2015 20:03:44 UTC+3, Norman J. Goldstein wrote: > In the case of shared_ptr's, it is wrong, in my situation, to take a > NULL pointer as a shared reference. I am interested only in the > relationship reflected by the use_count(). The 'use_count()' is required to return zero when 'shared_ptr' is empty. So if you are not interested in the situation (for example since there is nothing further to serialize) then why you care if they compare equal or no? > object is NULL, the relationship between the two shared_ptr's is > maintained. The use_count() is (at least) two for the two shared_ptr's, > even if they are sharing only NULL. Every 'shared_ptr<X>' is separate and if one starts to point at something else then others don't. > On 04/12/2015 06:29 AM, Öö Tiib wrote: Following was written by Paavo Helde: > As pointed out, above, shared_ptr's do remember the relationship, even > if they are assigned NULL. The point I am making is that I would like > to be able to query that relationship, even if the pointer value is NULL. They aren't required to remember any relationships; empty 'shared_ptr' is empty regardless if the object at what it pointed still exists or not. I am not sure what relationship. That was written by me: > I'm sorry, I don't understand these suggestions. The reason that I want > the id() feature, is so that I can save shared_ptr's to disk, and when > they get restored to RAM, they maintain the same relationship. http://isocpp.org/wiki/faq/serialization The 'shared_ptr' is like ordinary pointer that can point at object at what other pointers can point too. It does not provide indexing services. So you have to maintain some map (for example like 'std::map<std::weak_ptr<X>,unsigned>' or 'std::map<X const*,unsigned>') to map the shared object you serialize to some numeric id. > Currently, when the shared_ptr's are NULL, I cannot do this. During the > running of the program, one of the shared_ptr's might do a reset( new T > ), and all the (intended) shared_ptr's must see the change. I do not understand. Lets imagine there are two 'shared_ptr's p1 and p2 and two objects o1 and o2. All the 9 combinations of states of pointers is on following diagram: p1 | p2 -------------- 1) null | null 2) null | o1 3) null | o2 4) o1 | null 5) o1 | o1 6) o1 | o2 7) o2 | null 8) o2 | o1 9) o2 | o2 What is the difference for p2 if the state transits from 1) to 4) or if the state transits from 5) to 8)? It can't see anything anyway ... it still is empty or points at o1 and it does not know where p1 points. Please clarify where is difference and why they should not compare equal in state 1). |
"Norman J. Goldstein" <normvcr@telus.net>: Apr 12 01:09PM -0700 NULL and empty are not the same thing for shared_ptr. /////////////////////////////// #include <iostream> #include <memory> using namespace std; int main( int argc, char* argv[] ) { shared_ptr< int > s1; shared_ptr< int > s2( s1 ); cout << "s1 links= " << s1.use_count() << endl; cout << "s2 links= " << s2.use_count() << endl; s1.reset( (int*)nullptr ); s2 = s1; cout << "s1 links= " << s1.use_count() << endl; cout << "s2 links= " << s2.use_count() << endl; return 0; }// main //////////////////////////////// Here is the output of the program: s1 links= 0 s2 links= 0 s1 links= 2 s2 links= 2 On 04/12/2015 12:18 PM, Öö Tiib wrote: |
"Norman J. Goldstein" <normvcr@telus.net>: Apr 12 01:29PM -0700 I think I understand, now, what you are saying. If the shared_ptr's are managing a NULL, there is no way to get the same set to manage an actual object. Each shared_ptr contains a pointer to the object. I had imagined that the pointer to the object was actually in the control block. Thank you. |
"Öö Tiib" <ootiib@hot.ee>: Apr 12 02:09PM -0700 On Sunday, 12 April 2015 23:29:29 UTC+3, Norman J. Goldstein wrote: > Each shared_ptr contains a pointer to the object. I had imagined that > the pointer to the object was actually in the control block. > Thank you. It is bit trickier than that. The shared_ptr has 13 constructors 9 of what are templates so it can be made to do huge pile of tricks. There are two object pointers. What shared pointer "owns" (IOW to what will be called deleter when the use count drops to zero) is pointed by control block. What shared_ptr "points at" is in shared_ptr itself. |
"Öö Tiib" <ootiib@hot.ee>: Apr 12 05:08AM -0700 On Friday, 10 April 2015 18:12:08 UTC+3, Scott Lurndal wrote: > >either. > Although it works in all of the BCD, EBCDIC, UTF-8 (ASCII subset) and > USASCII codesets. It is also required by standard to work both in C ([5.2.1]/2) and in C++ ([lex.charset]/3). |
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