Friday, May 1, 2015

Digest for comp.lang.c++@googlegroups.com - 15 updates in 5 topics

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: