- Returning Function Pointers - 7 Updates
- Function Objects - 2 Updates
- Onwards and upwards - 2 Updates
- Container that has iterators to itself in the value_type - 2 Updates
- In need of reading material - 2 Updates
Doug Mika <dougmmika@gmail.com>: May 01 10:58AM -0700 Well, I found something on function pointers, but id didn't cover how it looks when your function returns these. That is, until I found the following piece of code I attach below #include <math.h> #include <stdio.h> enum { OPER_SIN, OPER_COS, OPER_TAN, OPER_SQUARE }; struct oper { int type; double (*func)(double); }; double square(double val) { return val * val; } struct oper oper_lut[] = { {OPER_SIN, sin}, {OPER_COS, cos}, {OPER_TAN, tan}, {OPER_SQUARE, square}, }; double (*get_oper(int oper_type))(double) { int n; for (n=0;n<(sizeof(oper_lut)/sizeof(oper_lut[0]));n++) { if (oper_type == oper_lut[n].type) { return oper_lut[n].func; } } } void apply_operation(double *dat, int length, double (*oper)(double)) { int k; for (k=0;k<length;k++) { dat[k] = oper(dat[k]); } } void print_vector(double *dat, int length) { int k; for (k=0;k<length;k++) { printf("%g ", dat[k]); } printf("\n"); } void call_it(void) { double vals[] = {1,2,3}; double (*func)(double); func = get_oper(OPER_SIN); apply_operation(vals, sizeof(vals)/sizeof(vals[0]), func); print_vector(vals, sizeof(vals)/sizeof(vals[0])); func = get_oper(OPER_COS); apply_operation(vals, sizeof(vals)/sizeof(vals[0]), func); print_vector(vals, sizeof(vals)/sizeof(vals[0])); func = get_oper(OPER_TAN); apply_operation(vals, sizeof(vals)/sizeof(vals[0]), func); print_vector(vals, sizeof(vals)/sizeof(vals[0])); func = get_oper(OPER_SQUARE); apply_operation(vals, sizeof(vals)/sizeof(vals[0]), func); print_vector(vals, sizeof(vals)/sizeof(vals[0])); } int main(int argc, char *argv[]) { call_it(); } I had two questions regarding this: 1) (I don't know why but this struct definition seems more complicated than necessary) What is this below, a struct or an array?: struct oper oper_lut[] = { {OPER_SIN, sin}, {OPER_COS, cos}, {OPER_TAN, tan}, {OPER_SQUARE, square}, }; 2) What is this: double (*get_oper(int oper_type))(double) |
Victor Bazarov <v.bazarov@comcast.invalid>: May 01 03:24PM -0400 On 5/1/2015 1:58 PM, Doug Mika wrote: > Well, I found something on function pointers, but id didn't cover > how it looks when your function returns these. That is, until I found the following piece of code I attach below > I had two questions regarding this: > 1) (I don't know why but this struct definition seems more > complicated than necessary) What is this below, a struct or an array?: > {OPER_TAN, tan}, > {OPER_SQUARE, square}, > }; You need to learn to read declarations. It will help a lot. Start with the name (can you identify the name here? It's "oper_lut"), then look to the *right*. If there is no bracket, you then proceed to the *left*. If there is a bracket, you proceed to say "is an array", so you get so far oper_lut ...(to the right there is a bracket) ... is an array of (how many elements? we don't know, the bracket closes before the size is specified) ... unknown size ... of (continue to the right, there is an equal sign, which means there is an initializer, which is not part of the declaration, so we reverse the direction)... "struct oper". Anything else? Nothing. So, what did we get? 'oper_lut' is an array of unknown size of 'struct oper'. A better approach can be found on the web, I've seen it, and I am sure you can find it. Look for "how to read C++ declarations" > 2) What is this: > double (*get_oper(int oper_type))(double) Same approach. Can you find the name? is 'oper_type' the name of the object being declared? Hint: no. What else can be a name? Hint: it's actually 'get_oper'. So you look to its *right*, you don't see a bracket, so (it's not an array) you reverse the direction. You see the asterisk. It's _a_pointer_ ! To what? Keep going... Drat, a closing (if going in that direction) parenthesis. Revers the direction. An opening parenthesis, followed by a declaration. An argument list! So, we say "a function that takes {all embedded declarations go here}" and keep naming those until we find a closing parenthesis, which is very close. What did we get so far? " 'get_oper' (to the left)... is a pointer (reverse the direction) ... to a function that takes one argument of type int" Now, we need to know what that function with one int argument returns, right? So we keep going in the same direction (which was to the right). Drat, another opening parenthesis. What does a parenthesis say? Depends on what's inside. And inside is a declaration (it's a bare type), so we add "a function that takes". What follows? The argument list -- "a double". Closing parenthesis means we keep going, but we see it's the end of the declaration. So we reverse direction to say "and returns"... What's left? The return type -- "a double". That is, we get "'get_oper' is a pointer to a function that takes one int and returns a function that takes a double and returns a double." That's not easy. You'll get the hang of it eventually, though. Since a function cannot be returned, a function that returns a function simply returns a _pointer_ to a function. V -- I do not respond to top-posted replies, please don't ask |
Doug Mika <dougmmika@gmail.com>: May 01 01:04PM -0700 > {OPER_TAN, tan}, > {OPER_SQUARE, square}, > }; Even with your explenation, since oper is defined as a struct shouldn't we write: oper oper_lut[] = { {OPER_SIN, sin}, {OPER_COS, cos}, {OPER_TAN, tan}, {OPER_SQUARE, square}, }; this is what's so unusual, why is the keyword "struct" in front of the array declaration? |
Victor Bazarov <v.bazarov@comcast.invalid>: May 01 04:11PM -0400 On 5/1/2015 4:04 PM, Doug Mika wrote: > {OPER_SQUARE, square}, > }; > this is what's so unusual, why is the keyword "struct" in front of the array declaration? Nothing. It's a C-ism. BTW, it's not in front of an array declaration. It's in front of 'oper' token, which by itself a "type-id." Supplied with the 'struct' it turnes into an "elaborate type specifier". It's perfectly fine without it, but in C we can't use 'oper' as a type in a declaration, unless it's declared using a typedef, and we have to use 'struct' in front of it to designate that 'oper' should be looked up among some struct definitions (or declarations, I don't remember what they are called in C). In C++ we don't need to do it *except* to solve ambiguity. In this particular case there is no ambiguity. The code was probably written by a C programmer... V -- I do not respond to top-posted replies, please don't ask |
Ben Bacarisse <ben.lists@bsb.me.uk>: May 01 11:51PM +0100 Victor Bazarov <v.bazarov@comcast.invalid> writes: <snip> > You need to learn to read declarations. It will help a lot. Yes, but it's tricky... <snip> > A better approach can be found on the web, I've seen it, and I am sure > you can find it. Look for "how to read C++ declarations" I wrote one, but reading it over just now I'm not sure that it's any better than the others: http://www.bsb.me.uk/c-types > On 5/1/2015 1:58 PM, Doug Mika wrote: <snip> >> 2) What is this: >> double (*get_oper(int oper_type))(double) <snip discussion> > That is, we get > "'get_oper' is a pointer to a function that takes one int and returns > a function that takes a double and returns a double." No, it's a function taking an int and returning a pointer to a function taking a double and returning a double. <snip> -- Ben. |
Ben Bacarisse <ben.lists@bsb.me.uk>: May 01 11:54PM +0100 Victor Bazarov <v.bazarov@comcast.invalid> writes: <snip> > In C++ we don't need to do it *except* to solve ambiguity. In this > particular case there is no ambiguity. The code was probably written > by a C programmer... It probably was, but that sounds a little dismissive -- it may have been written by a C programmer because it's C! (There's a fair bit of evidence that the posted code is C not C++ though one can rarely be 100% sure.) -- Ben. |
Ben Bacarisse <ben.lists@bsb.me.uk>: May 02 12:00AM +0100 Doug Mika <dougmmika@gmail.com> writes: <snip> > I had two questions regarding this: > 1) (I don't know why but this struct definition seems more complicated > than necessary) What is this below, a struct or an array?: It's an array. > {OPER_TAN, tan}, > {OPER_SQUARE, square}, > }; The code is (probably) written in C, so the element type is "struct oper". All struct types start "struct ..." in C. > 2) What is this: > double (*get_oper(int oper_type))(double) It's a function taking an int and returning a pointer to a function that takes a double and returns a double. It is generally clearer to write such types using type definitions for the parts: typedef double operation(double); operation *get_oper(int oper_type); (and you'd use that type in the struct as well). -- Ben. |
Jorgen Grahn <grahn+nntp@snipabacken.se>: May 01 05:34PM On Thu, 2015-04-30, 嘱 Tiib wrote: > On Thursday, 30 April 2015 21:00:42 UTC+3, Doug Mika wrote: ... > C++ standard does say "automatic storage" (that is usually stack) and > "dynamic storage" (that is usually heap). It does not specify if > temporaries are stored in either (but usually it is stack as well). Nitpick: might just as well be in registers, or optimized away partially or completely. Thinking of it as "on the stack" works for me, but I don't want people to avoid creating classes because they think using raw ints or whatever is more efficient. /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
Victor Bazarov <v.bazarov@comcast.invalid>: May 01 02:03PM -0400 On 5/1/2015 1:34 PM, Jorgen Grahn wrote: > partially or completely. Thinking of it as "on the stack" works for > me, but I don't want people to avoid creating classes because they > think using raw ints or whatever is more efficient. ... and don't forget that sometimes it's up to the object itself to use freestore to deposit some additional information that it needs during its lifetime (however short). For instance, it's *unlikely* that a *temporary* vector of [some large number] of elements is all going to resign in registers or on the stack. You're free to thing of it as "on the stack", but you will most probably be mistaken. A few bytes on the stack can mean *any* amount on the heap, as well. Just a thought... V -- I do not respond to top-posted replies, please don't ask |
woodbrian77@gmail.com: May 01 09:00AM -0700 On Thursday, April 30, 2015 at 2:16:10 PM UTC-5, Ian Collins wrote: > I think you are missing the point - throwing an exception is an > exceptional event and the cost of constructing an exception object is > seldom a concern given all of the other overheads involved. I think a ctor like that is useful beyond exception handling. Rather than reserving enough space for the whole string and then assigning the first part of the string, let the ctor figure out how long the first part is and you only have to tell it how much additional space to allocate. Brian Ebenezer Enterprises - G-d loves you. http://webEbenezer.net |
woodbrian77@gmail.com: May 01 09:28AM -0700 > then assigning the first part of the string, let the ctor > figure out how long the first part is and you only have to > tell it how much additional space to allocate. A ctor that takes two "char const*" would also be helpful for reasons similar to those I mentioned previously. Brian Ebenezer Enterprises http://webEbenezer.net |
Marcel Mueller <news.5.maazl@spamgourmet.org>: May 01 09:10AM +0200 On 29.04.15 01.49, Victor Bazarov wrote: > map contains one element, and therefore its iterators are now end() > (which is kept in the first element) and the one that is not 'end()', > i.e. the iterator to the "first" entry, whose content is 'end()', yes? Exactly. > first non-end() iterator. That is, your map now contains two entries, > the first of which is 'end()', the other is the iterator of the "real" > element... And so on. The other way around. Inserting the second element changes the first elements iterator (= value) to the iterator returned by the second insertion. The lastly inserted element always has the value end(). The iterator to the last insert, named tail, is kept outside to setup the value to link to the next insertion. >> one is changed to the iterator returned from the second insert and so >> forth. > When? And where is the consistency of the map? Changing values does not effect the consistency of the map. > What is it you're trying to model with that paradoxical structure? And > why a map? If you need a circular buffer, find and use a circular > buffer. I am sure there are numerous examples of such an adapter. It is a moving median filter. Take a floating point value stream and calculate the median for every N consecutive values. If I use ordinary median calculations I need to perform a sort of every consecutive set of N values, ending up with a complexity of O(M N log N) with M = stream length and N = window size. But when I am able to transform the sorted set of values[0:N] into values [1:N+1] then it is significantly faster. All I need to know for this purpose is the oldest value to remove it. So a linked list fits best. And for the sorted set I need to have iterators that survive insertions and deletions. That's why the map. The complexity is now O(M log N) which is quite fast. Using a custom allocator that always allocates from a pool of exactly N entries will furthermore remove any memory allocations from the stream processing code. Marcel |
Marcel Mueller <news.5.maazl@spamgourmet.org>: May 01 11:54AM +0200 On 29.04.15 20.50, K. Frank wrote: > the language / standard library to provide such functionality > for iterators? (And would it be possible, given that > standard-library collections are templates?) To make this work it is required that the footprint of the iterator does not depend on the type arguments of the container. AFAIK there is no such guarantee. This concept requires type erasure rather than templates. Of course, one could build containers that satisfy this need, since it is uncommon that iterators depend on the element type other than for the purpose of strongly typed methods and type safety. (I have already seen iterators that store a copy of the current element - not with C++, of course.) However, even if it is quite trivial to implement the type erasure from the container's point of view I have no idea how to get a type safe syntax for the language. This would require to define iterator types with incomplete types. And unfortunately nested types do not allow forward declarations. (An annoying restriction.) [... some tests later] At least gcc 4.8 eats this: #include <map> #include <stdio.h> using namespace std; int main() { struct elem; typedef multimap<int,elem> map_type; typedef map_type::iterator iter_type; struct elem : public iter_type { elem(const iter_type& i) : iter_type(i) {} }; map_type my_map; auto first = my_map.emplace(1,my_map.end()); auto last = first; last = last->second = my_map.emplace(0,my_map.end()); last = last->second = my_map.emplace(3,my_map.end()); // access by sequence for (auto cur = first; cur != my_map.end(); cur = cur->second) printf("%i\t", cur->first); putchar('\n'); // access by key for (auto cur : my_map) printf("%i\t", cur.first); putchar('\n'); return 0; } But I did not succeed without the helper struct since you cannot forward declare a typedef, isn't it? Although this work around is quite tolerable since it neither causes runtime overhead nor code bloat. Furthermore I am unsure whether this is a feature of gcc or it is covered by the standard. And, of course, it would be even more pretty w/o the helper struct. Marcel |
ram@zedat.fu-berlin.de (Stefan Ram): Apr 30 11:17PM >When you pass the name of a function as a parameter ... ^^^^^^^^^ >void g(void fn()) ... > g(f); Above, »f« is an /argument/ (5.2.2), »fn« is a /parameter/ (8.4). >The names of functions always implicitly decay to a pointer to the >function. Not always! For example, when template< typename T > void m( T & param ); if called with the function name »f«, then the deduced parameter-type will be »reference to function«, so the name »f« has not decayed into a pointer to the function. |
ram@zedat.fu-berlin.de (Stefan Ram): Apr 30 11:26PM >Are these really called "lvalue references" now? In 3.9.2, »lvalue reference« is used, but it is possible that the community of programmers will not pick up this designation. |
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