- enum type in template declaration - 11 Updates
- What does the "L" mean - 8 Updates
- issues with std::variant - 6 Updates
| James Kuyper <jameskuyper@alumni.caltech.edu>: Dec 05 10:39PM -0500 On 12/5/19 5:20 PM, Soviet_Mario wrote: > since what version of standard, if any, an ENUM type can be > an argument of a template ? It has always been possible to use an enumerated type as a template parameter. There is no special rule giving a enumerated type any different status from any other type in that regard. > sth like > enum RestrictedValues { A = 1, B = 2, C = 4, D = 8 }; > template <RestrictedValues ttVal> class SizedField However, you're not using an enumerated type as a template argument, you're using a enumeration value. That is a marginally newer feature of C++, though I believe that it still pre-dates the first version of the standard. There is no distinction for this purpose between values of enumerated type and those of any other integer type. |
| Soviet_Mario <SovietMario@CCCP.MIR>: Dec 06 01:15PM +0100 Il 06/12/19 04:39, James Kuyper ha scritto: >> an argument of a template ? > It has always been possible to use an enumerated type as a template > parameter. sorry I'm not sure I have understood Do you mean to use it as just a VALUE (instancing it) in an generic integral parameter, or a proper TYPE-CHECKED declaration (so that giving non typed integer value while instancing would give a compile error) ? > There is no special rule giving a enumerated type any > different status from any other type in that regard. Uhm ... ok, maybe I have outdated memories :\ >> template <RestrictedValues ttVal> class SizedField > However, you're not using an enumerated type as a template argument, > you're using a enumeration value. Mmmm, exactly the point I am misunderstanding. I believed to have been able to establish a proper type-checking in that declaration. How instead it should have been written ? can you correct my example in order to non accept non specific-enum integral instancing ? -- 1) Resistere, resistere, resistere. 2) Se tutti pagano le tasse, le tasse le pagano tutti Soviet_Mario - (aka Gatto_Vizzato) |
| Paavo Helde <myfirstname@osa.pri.ee>: Dec 06 02:42PM +0200 On 6.12.2019 14:15, Soviet_Mario wrote: >> It has always been possible to use an enumerated type as a template >> parameter. > sorry I'm not sure I have understood A template parameter can be a type, an int, etc. An enum type is also a type: enum RestrictedValues { A = 1, B = 2, C = 4, D = 8 }; template<typename T> class A { T member; }; A<RestrictedValues> x; // OK Here, an enum type is used as an argument of a template, as you requested. However, I suspect that you actually want to use an enum value (not enum type) as the template parameter - see below. > How instead it should have been written ? > can you correct my example in order to non accept non specific-enum > integral instancing ? You have not said what your problem is. If you got a compiler error, then what was the code and what was the error? What you wrote was basically correct syntax (after commenting out "etc etc"). This compiles fine: enum RestrictedValues { A = 1, B = 2, C = 4, D = 8 }; template <RestrictedValues ttVal> class SizedField { private: unsigned char zzArray[ttVal]; public: //etc etc }; int main() { SizedField<B> foo; } |
| "Öö Tiib" <ootiib@hot.ee>: Dec 06 06:00AM -0800 On Friday, 6 December 2019 14:15:40 UTC+2, Soviet_Mario wrote: > How instead it should have been written ? > can you correct my example in order to non accept non > specific-enum integral instancing ? We can easily help but right now your descriptions of problem are too confusing to decipher (at least for me). Please write compiling example (no pseudocodes) what you want to achieve. What code compiles (or picks partial specialization that you don't want it to pick) but you want it not to compile (or to pick some other specialization). |
| James Kuyper <jameskuyper@alumni.caltech.edu>: Dec 06 09:56AM -0500 On 12/6/19 7:15 AM, Soviet_Mario wrote: > generic integral parameter, or a proper TYPE-CHECKED > declaration (so that giving non typed integer value while > instancing would give a compile error) ? Neither. I'm talking about a type, not a value. You, on the other hand, were talking about a value, but referring to it as a type, which is connected closely to the source of your confusion. I'll explain that in more detail in my response to your later questions. >> There is no special rule giving a enumerated type any >> different status from any other type in that regard. > Uhm ... ok, maybe I have outdated memories :\ I suspect it's not your memories that are the problem, but your understanding of the issue. > Mmmm, exactly the point I am misunderstanding. I believed to > have been able to establish a proper type-checking in that > declaration. There's nothing wrong with that declaration, as such. It just has nothing to do with the contents of the sentence you started your message with. What you refer to in that sentence would match the following code: #include <vector> std::vector<enum RestrictedValues> vrv; The type "enum RestrictedValues" is allowed as an argument the the std::vector template class, and that has always been allowed, for as long as C++ (which wasn't known as C++ yet, at the time this feature was added) has had templates. Your code does NOT use a enumerated type as a template argument. It uses a enumeration value as an argument. ttVall above is example of what is called a template non-type argument. I believe that those were a somewhat later addition to the language, but I also believe that they were already fully supported before I first learned about C++, would would have been in the late 1980s, well before the first version of the C++ standard was approved. The latest draft standard I have is n4659.pdf. Template non-type arguments are described in section 17.3.2: > (2.3) — a string literal (5.13.5), > (2.4) — the result of a typeid expression (8.2.8), or > (2.5) — a predefined __func__ variable (11.4.1). ttVall is type-checked. However, C++ allows the creation of values of enumerated type that don't match any of the enumeration constants associated with that type - see 10.2p8 for a precise specification of the range of values permitted. Your template can therefore be instantiated with any of those other values, which I suspect is not what you want. However, something that might work as you might like is to declare a template class, but with no definition for that class. Provide explicit specializations of the template for the particular values you want supported, which don't use the generic definition. Then any use of the template that doesn't match one of the specializations will produce an error message. Here's some simplified example code: #include <iostream> enum mybool {FALSE, TRUE}; template <mybool val> struct boolname; template <> struct boolname<FALSE> { const char *name() const { return "False";}; }; template <> struct boolname<TRUE> { const char *name() const { return "True";}; }; int main(void) { boolname<FALSE> t; std::cout << t.name() << std::endl; return 0; } If you change the final occurrence of FALSE in that code with static_cast<mybool>(2), it will fail at compile time with a diagnostic, because their is no specialization for that value, and no generic definition of the template that could be used for unspecialized values. |
| Manfred <noname@add.invalid>: Dec 06 03:56PM +0100 On 12/6/2019 1:15 PM, Soviet_Mario wrote: > How instead it should have been written ? > can you correct my example in order to non accept non specific-enum > integral instancing ? As other have pointed out, it appears that what you want is a template with a "non-type template parameter", the parameter being an enum value. I did not check the standard, but it appears that this gives the type checking you are looking for. following up on the sample from Paavo: > }; > int main() { > SizedField<B> foo; SizedField<42> bar; > } This is what gcc reports: $ c++ -std=c++17 -Wall templateArgEnum.cc templateArgEnum.cc: In function 'int main()': templateArgEnum.cc:22:16: error: invalid conversion from 'int' to 'RestrictedValues' [-fpermissive] 22 | SizedField<42> bar; | ^ | | | int templateArgEnum.cc:21:17: warning: unused variable 'foo' [-Wunused-variable] 21 | SizedField<B> foo; | ^~~ templateArgEnum.cc:22:18: warning: unused variable 'bar' [-Wunused-variable] 22 | SizedField<42> bar; | ^~~ |
| Soviet_Mario <SovietMario@CCCP.MIR>: Dec 06 05:20PM +0100 Il 06/12/19 13:42, Paavo Helde ha scritto: > you requested. > However, I suspect that you actually want to use an enum > value (not enum type) as the template parameter - see below. none of both : I would like to declare that a parameter must be of enum type, so that the values actually received by the actual instance are not simply generic integral, but a selected subset. Assume you would like to model a "pixel" with a variable depth of color, but that such depth should be checked (at compile time) to be a power of two, and set up an enum like enum EnumDepths { two = 2, four = 4, eight = 8 } then the template should not take a simple integral paramenter, as one could instantiate it wrongly template <3> class ClsBMPofPixels; so the typename must be of EnumDepths type, and only after this compile time check, yes, then internally the VALUE passed is used practically >> integral instancing ? > You have not said what your problem is. If you got a > compiler error, then what was the code and what was the error ? no, still just trying to figure out and think, not yet any practical code > int main() { > SizedField<B> foo; > } yes but would such code protect me from writing template <5> class SizedField; ? Would the compiler check that 5 is not a legal value of the enum ? If so, okay ... Oh, but BTW, what "helper" functions about run-time INTROSPECTION are more or less standard ? I've found some is_enum<EnumType> (), is_array<typename> () and so. But a simple function like : bool is_of_type <typename> () in other languages such operators are named like "TypeOf" (or typename, also a string representation could be usefull) This question is for a concrete case. I'm trying to build a 2D table container not particularly generic : it supports just two type of contained items, either double either a "fixed size string", but I'm not sure I'd be able to write really generic functions as the two basic types contain some equivalent operators, constructors and comparison op, but also some semantically different accessors for higher level function on a container. So I'd appreciate some way a container could look inside himself (at runtime) and be aware of its type and call proper specialized functions where the syntax are not equivalent and I cannot rely only on overload for automatic selection of the best fit, or even in case I have to choose to MIX data, thing that will end in ambiguity, as the two types (fixedstrings and double) are largely convertible and interchangeable, so a generic function with identical signatures could not know what is the best to be called) -- 1) Resistere, resistere, resistere. 2) Se tutti pagano le tasse, le tasse le pagano tutti Soviet_Mario - (aka Gatto_Vizzato) |
| Soviet_Mario <SovietMario@CCCP.MIR>: Dec 06 06:43PM +0100 Il 05/12/19 23:20, Soviet_Mario ha scritto: tnx for all for elucidations. I still have some confused ideas about template instancing, but I don't know exactly what to ask. So I make more "experiments" before. Ciao -- 1) Resistere, resistere, resistere. 2) Se tutti pagano le tasse, le tasse le pagano tutti Soviet_Mario - (aka Gatto_Vizzato) |
| Paavo Helde <myfirstname@osa.pri.ee>: Dec 06 08:29PM +0200 On 6.12.2019 18:20, Soviet_Mario wrote: > yes but would such code protect me from writing > template <5> class SizedField; ? Would the compiler check that 5 is not > a legal value of the enum ? Yes, it will check. Why don't you try it out by yourself? num RestrictedValues { A = 1, B = 2, C = 4, D = 8 }; template <RestrictedValues ttVal> class SizedField { private: unsigned char zzArray[ttVal]; public: //etc etc }; int main() { SizedField<3> foo; } 1>main.cpp 1>d:\test\consoletestvs2017\consoletestvs2017\main.cpp(16): error C2440: 'specialization': cannot convert from 'int' to 'RestrictedValues' 1>d:\test\consoletestvs2017\consoletestvs2017\main.cpp(16): note: Conversion to enumeration type requires an explicit cast (static_cast, C-style cast or function-style cast) 1>d:\test\consoletestvs2017\consoletestvs2017\main.cpp(16): error C2973: 'SizedField': invalid template argument 'int' 1>d:\test\consoletestvs2017\consoletestvs2017\main.cpp(4): note: see declaration of 'SizedField' However, 'SizedField<RestrictedValues(3)> foo;' compiles. I would not worry about that, in C++ one can always find ways to shoot himself. > But a simple function like : bool is_of_type <typename> () > in other languages such operators are named like "TypeOf" (or typename, > also a string representation could be usefull) C++ is pretty statically typed, so you typically do not need things like TypeOf to find out the type at run time. For polymorphic types there is typeid() though which is similar, and also provides name() (which is not guaranteed to be useful). > (fixedstrings and double) are largely convertible and interchangeable, > so a generic function with identical signatures could not know what is > the best to be called) You have to make up your mind if you have the type (double or string) fixed at compile time or at run time. If at compile time, then there is no need for the container to check the type at run time, as the type was already fixed at the compile time and cannot change. E.g. a std::vector<double> does not need to check at run-time if its elements have suddenly turned into strings. If the item type only becomes known only at run time, then it most probably means you have some variant type. For this custom variant type there are no overloaded functions present, you have to write them yourself, and there you have to figure out the correct type at run-time and act accordingly. |
| Soviet_Mario <SovietMario@CCCP.MIR>: Dec 06 10:42PM +0100 Il 06/12/19 19:29, Paavo Helde ha scritto: > On 6.12.2019 18:20, Soviet_Mario wrote: >> Il 06/12/19 13:42, Paavo Helde ha scritto: TNX (for the 1st part) > However, 'SizedField<RestrictedValues(3)> foo;' compiles. I > would not worry about that, in C++ one can always find ways > to shoot himself. ok, this kind of mistakes worries me less than simple slight >> the best to be called) > You have to make up your mind if you have the type (double > or string) fixed at compile time or at run time. they will exist both, and interact from time to time (mutual conversions, plus some calculations done in string mode, like dates comparisons and some sorting in names/surnames fields, and other in "double mode", statistics on data. The two tables have to stay synced when one is sorted and the other driven together) > the compile time and cannot change. E.g. a > std::vector<double> does not need to check at run-time if > its elements have suddenly turned into strings. it is the template function that is generic and has to know to cope with both in different semantically ways, or no ? > If the item type only becomes known only at run time, then > it most probably means you have some variant type. uhm ... the allocation of proper types is known, but at "CODE-TIME" some functions have duplexed code, and must know which part to use according to the actual type of the container caller. Maybe this arises from bad design of the functions, dunno :( anyway I'll study typeid and type_info keywords. Tnx -- 1) Resistere, resistere, resistere. 2) Se tutti pagano le tasse, le tasse le pagano tutti Soviet_Mario - (aka Gatto_Vizzato) |
| Paavo Helde <myfirstname@osa.pri.ee>: Dec 07 12:51AM +0200 On 6.12.2019 23:42, Soviet_Mario wrote: > uhm ... the allocation of proper types is known, but at "CODE-TIME" some > functions have duplexed code, and must know which part to use according > to the actual type of the container caller. Sorry, I cannot make heads or tails out of your babble, but as it seems you are fascinated by templates and not really comprehending them, here are some general remarks about them which might be helpful. I know this can be confusing, but in C++ it is actually pretty simple: templates are a compile-time feature. If you need something to be solved by template mechanisms, it must be known at compile time. And vice versa, if something is only known only at run-time, you have to do it in an old-fashioned run-time way - an if, a switch, etc. hth |
| Vir Campestris <vir.campestris@invalid.invalid>: Dec 06 10:59AM On 05/12/2019 15:31, Ben Bacarisse wrote: > That also should work on a bit-addressed machine. You mean, I think, > that the code assumes some very specific things about the manipulation, > most probably that (int)(p + 1) == (int)p + sizeof *p. You could write code that worked on that TI chip, making assumptions about the way the addresses work. You could also write code that works on the 99% of machines where char vec[2]; assert(((int)&vec[1] - (int)vec) == 1); works. BTW the Dec10 - the 36 bit one I used - an int was 36 bits, but a character string was stored as set of 5 7-bit ASCII characters plus one pad bit in each word... Never used C on it though. Andy |
| Bart <bc@freeuk.com>: Dec 06 04:20PM On 04/12/2019 08:40, Paavo Helde wrote: > years ago, and MS used it a lot instead of 16-bit int (which was indeed > unusable for many purposes). As a result, now they cannot change 'long' > to 64-bit because they have abused it so much. At least, on Windows 'long' is consistently 32-bit. On Linux, as I understand it, 'long' is either 32 bits or 64 bits, depending on whether the OS is 32 or 64 bits. This means that if you use 'long' on Linux64, and depend on it being 64 bits, the same program might not work properly on Linux32. And if a 'long' is wide enough on Linux32, then on Linux64 it will wastefully be 64 bits (ie. an array of 'long' takes twice the memory). (Suggestion: don't bother with 'long' at all; either use plain int (32 bits on most relevant machines), or long long int (64 bits), which has the -LL suffix for constants that need to be considered 64 bits.) |
| boltar@nowhere.co.uk: Dec 06 04:30PM On Fri, 6 Dec 2019 16:20:07 +0000 >(Suggestion: don't bother with 'long' at all; either use plain int (32 >bits on most relevant machines), or long long int (64 bits), which has >the -LL suffix for constants that need to be considered 64 bits.) #include <stdint.h> int32_t myint; int64_t mylong; uint32_t myuint; uint64_t myulong; Sorted. |
| scott@slp53.sl.home (Scott Lurndal): Dec 06 04:36PM >(Suggestion: don't bother with 'long' at all; either use plain int (32 >bits on most relevant machines), or long long int (64 bits), which has >the -LL suffix for constants that need to be considered 64 bits.) Even better. Use the standard types uint64_t or uint_least64_t if you need values in the range 0 .. 2^64-1, or int64_t/int_least64_t if you need values in the range -2^63 .. +2^63-1. |
| Bart <bc@freeuk.com>: Dec 06 05:50PM > #include <stdint.h> > int32_t myint; > int64_t mylong; So, do you write 3, 3L or 3LL if you wanted three be considered a 'long' type in calculations? If you need to use a format code (I don't know how much that is still prevalent in C++), is it %d, %ld or %lld? > Sorted. You use a library where the author also 'sorted' by using a type 'mylong'. Is a mylong* of your type compatible with a mylong* of theirs? (Ignoring the name clashing, but the question would still be how your mylong1 relates to their mylong2.) |
| scott@slp53.sl.home (Scott Lurndal): Dec 06 06:18PM >> int64_t mylong; >So, do you write 3, 3L or 3LL if you wanted three be considered a 'long' >type in calculations? Yes. |
| Bart <bc@freeuk.com>: Dec 06 08:44PM On 05/12/2019 15:15, Vir Campestris wrote: > sizeof is interesting when things don't have to be whole numbers of > bytes. (you have a greyscale graphics plane with 3 bits per pixel, > 800x600. How much RAM is that? Actual physical memory, or address space? On this thing it was literally 3 _bits_ > x800x600, when most machines would end up unpacking the pixels into bytes.) I made one device (video memory) that used 1024 x 6 bits. Total physical RAM: 768 bytes; address space: 1KB. Another that used 16K x 4 bits. Total physical RAM: 8KB; address space: 16KB. Unless this is a special kind of memory known to the language, it will be working with the address space. |
| Bart <bc@freeuk.com>: Dec 06 08:52PM On 04/12/2019 21:46, Vir Campestris wrote: > bit. Other values are available :( > The one that really strained C was the one where incrementing a pointer > by 1 went to the next bit. Not byte or word. (TI GPU) You'd think the compiler would turn ++p into the correct step then. p would have to be a pointer not an int containing a point. But then it wouldn't work properly on x64 or ARM either. > The one with 36 bits (DECSystem10) an address was the address of a word, > and you couldn't point to a character inside the word. I didn't use C on > it. That machine had a hardware extension allowing you to refer to bytes (of any width) inside a word using special instructions. This used spare bits in the top half a word, while the bottom half was the word address. So simply incrementing such a pointer would step to the next word not the next byte. A language would need to be aware of this scheme so that ++p would step to the next byte. |
| "Öö Tiib" <ootiib@hot.ee>: Dec 05 03:41PM -0800 On Thursday, 5 December 2019 23:42:30 UTC+2, Taylor wrote: > > What have diffs to do with Memento pattern? Utter nonsense. > > Read at least Wikipedia article about it. > The chain of reversible operations (changes) you describe is error prone and requires additional complexity. So go ahead and store state of your whole document after each click. Or maybe even commit it to repo ... how should I care? > As an example, in Photoshop, Adobe has abandoned the chain reversible operations in favor of value oriented design. Who is there in Adobe? I know no one from it. Perhaps all the decent engineers who made it what it is have been eaten out. If whatever is left of it decides to rewrite their Acrobat in F# then should we follow? > I'd recommend watching Sean Parent's talks such as this one: https://www.youtube.com/watch?v=QGcVXgEVMJg. Scrolled a bit into that video. First he pushed rawly newed pointer to document then said that it is wrong and used the most dork tool std::make_shared! I stopped right there. Had it been std::make_unique I would had guessed that poor kid hasn't tried polycollections like you. But snake oil salesmen start from such clear idiocies for to ensure that by minute 7 everybody with at least half a brain are left away and only total morons remain. Do not post anymore YouTube crap. Watching such TV and movies is perhaps good entertainment for retarded and illiterate. > > at least tried the tutorials of it or something? > > Very confusing. > I've used flatbuffers extensively at this point. Sorry, it does not make any sense what is supposed to be the issue with it. Decent serialization library with bit more verbose interface than I would use. |
| Christian Gollwitzer <auriocus@gmx.de>: Dec 06 09:39AM +0100 Am 05.12.19 um 18:59 schrieb Taylor: >> but that the rest of the code relies on. > If I were to use inheritance to factor out commonality, I would need to use multiple inheritance and it could get messy. So for example, there's the base class Node, then there might be ExposedNode, and ColorfulNode, LabeledNode. > Or I could use interfaces, such has HasExposedPosition, HasColor, HasLabel, etc. I did this before and it's much more code than the variant stuff. I'm far from understanding the problem, but factoring out common members does not mean you nead "class A: public B" inheritance. You could also have a "struct Node" and then stuff the things that vary into the variant, which is a member of "Node". This is done in C with unions very often e.g. for byte code interpreters, where all the values have a type tag, a reference count, an alternative representation, and then a union which contains the real data. Christian |
| Christian Gollwitzer <auriocus@gmx.de>: Dec 06 09:58AM +0100 Am 05.12.19 um 18:44 schrieb Taylor: >> that is language- and platform-neutral ... that provides also wider >> opportunities of automatic black-box testing of your modules. ;) > I use Flatbuffers for serialization. It's pretty good. But it doesn't easily provide the structural sharing that I need to make undo/redo memory-efficient. For example, if my document contains large data (images, audio, etc.) I don't want to have to save that out after every user interaction. We used such a scheme for undo/redo in a project (written in another language, not C++). The document there consists of 3D meshes composed into a 3D scene and attached properties like material, transformation, ... So the actual data was quite small (few kb for a realistic document, even if stored in text format) compared to multi-MB of 3D mesh data. Even before we introduced undo/redo, the serialization format did not include the 3D meshes. There is a global storage of the big objects, a hash map indexed by the MD5 of the binary mesh data, and the document simply references these. On I/O, only the transformation data is serialized into a compact format and a second pass reads/writes the binary object table. The on-disc format in the end was a ZIP file, this is similar to modern text writer formats. Just rename a docx-file to .zip and open it up, then you'll see it uses the same scheme. Undo/redo with this scheme was instant, almost no memory consumption, so we could provide unlimited undo. Christian |
| "Öö Tiib" <ootiib@hot.ee>: Dec 06 06:06AM -0800 On Friday, 6 December 2019 10:58:47 UTC+2, Christian Gollwitzer wrote: > The on-disc format in the end was a ZIP file, this > is similar to modern text writer formats. Just rename a docx-file to > .zip and open it up, then you'll see it uses the same scheme. Yes, lot of projects use that format: folders of utf8 text and portable binary files zipped, just that json instead of xml is more usual. |
| Taylor <wtholliday@gmail.com>: Dec 06 09:12AM -0800 On Friday, December 6, 2019 at 12:39:47 AM UTC-8, Christian Gollwitzer wrote: > tag, a reference count, an alternative representation, and then a union > which contains the real data. > Christian Thanks Christian. That would be an improvement and cut down on the variant visitation (it would help compilation time on one file in particular). I don't think it would go far enough though in improving my compilation time. |
| Taylor <wtholliday@gmail.com>: Dec 06 09:44AM -0800 On Thursday, December 5, 2019 at 3:41:38 PM UTC-8, Öö Tiib wrote: > Scrolled a bit into that video. First he pushed > rawly newed pointer to document then said that it is wrong and used > the most dork tool std::make_shared! I stopped right there. You should continue watching. He's just using shared_ptr in his example. A production implementation would use a small-object optimization. In fact, central to his type erasure scheme is reducing the amount of dynamic allocation. |
| 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