Sunday, July 1, 2018

Digest for comp.lang.c++@googlegroups.com - 25 updates in 6 topics

Soviet_Mario <SovietMario@CCCP.MIR>: Jul 01 01:35PM +0200

I'm getting different errors when compiling and changing the
order of the files.
Now I still have clear enough notion of SCOPE of object, but
I must admit I have none about the sequence of scopes (the
"order" the files are compiled or, maybe, linked).
Is this relevant ?
 
For a proof I merged the content of four files that
generated errors (type not defined and so) and as a
monolitic file it compiles and links without error, so the
problem is in the order of declarations, but I don't know
well this topic.
 
If there is sb using QT creator, how is possible to control
this in the IDE ?
Or even better (but I'm not optimistic) : is it possible to
embed in CODE itself directives, pragmas or else, to control
the flow of compilation or linking ?
 
I tried to resort to include, but it didn't work ...
 
TY
 
 
--
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)
Tim Rentsch <txr@alumni.caltech.edu>: Jun 30 04:51PM -0700


> I can't recall having seen this approach, so posting it here:
 
> [..code was here..]
 
Interesting idea. Perhaps a little weird, but definitely
interesting!
 
Here is a somewhat different means of arranging the cleanup.
Note the single constructor call for 'Later it' below:
 
#include <iostream>
#include <string>
#include <functional>
#include <sstream>
 
using namespace std;
 
using Fixer = function< void() >;
 
class Later {
Fixer f;
public:
Later( Fixer f0 ) : f( f0 ) {}
~Later(){ f(); }
};
 
int
main( int argc, char *argv[] ){
Fixer supersede_with( const char * ), use_stdin();
bool faux = argc > 1 && string( argv[1] ) == "--faux-text";
cout << " With" << (faux ? "" : "out") << " other input:\n";
 
Later it( faux ? supersede_with( "Your ad here!" ) : use_stdin() );
cout << " (here we are running the app)\n";
}
 
Fixer
supersede_with( const char *other_input ){
cout << " 'supersede_with' starting - " << other_input << '\n';
istringstream in{ basic_string<char>( other_input ) };
streambuf *s{ cin.rdbuf() };
cin.rdbuf( in.rdbuf() );
 
return [=](){
cin.rdbuf( s );
cout << " 'supersede_with' ending - " << other_input << "\n";
};
}
 
Fixer
use_stdin(){
cout << " (any tests before using regular input...)\n";
return [](){
cout << " (we have been using regular input)\n";
};
}
 
 
Disclaimer: I am certainly not an expert in C++ lambdas. AFAICT
the above code is okay, but I confess my efforts to decipher what
the C++ standard says could not be called entirely successful.
Running the program produced the expected output in both cases.
 
(Also thanks due to Manfred, from whose program I cribbed a bit.)
Tim Rentsch <txr@alumni.caltech.edu>: Jun 30 11:07PM -0700


> On 06/27/2018 07:10 AM, Alf P. Steinbach wrote:
 
>> On 27.06.2018 09:36, David Brown wrote:
 
[...]
 
> initializers, or conditions in #if directives or if(), while(), do
> while(), and for() statements, or the first and third parts of a
> for().
 
What nonsense. There are plenty of places ?: can be used as part
of ordinary expressions that make a program shorter, simpler,
easier to read, and easier to understand.
 
> Even in those locations, it should only be used if it's actually
> clearer than the alternative (which would, generically, involve
> defining a function that contains those multiple statements).
 
The word "clearer" in this context is sufficiently vague and
subjective that this statement has almost no semantic content.
Christian Gollwitzer <auriocus@gmx.de>: Jul 01 08:48AM +0200

Am 29.06.18 um 06:08 schrieb Alf P. Steinbach:
 
>>      app::run();
 
> Here cleanup is performed before `app::run()`, which means it will never
> get executed with faux text.
 
As a non-expert C++ programmer, I could understand the intent of the
code and the intricacies of the , operator only after it was explained
here by several people. The ?: is not the problem, but in this code I
was heavily wondering how the hell can the app::run() access anything
from these with_stream... objects. The problem is the data flow via side
effects. It would have been different if it looked like
 
app::run(args[1] == "--faux-text" ? with_stream() : with_faux());
 
Or perhaps:
 
app App;
app.setStream(args[1] == "--faux-text" ? with_stream() : with_faux())
app.run();
 
And instead of with_stream() etc. modifying global objects, it should
return a stream object to be read from.
 
In that case it is very clear how the information passes on to app::run.
Modifying a global state from within a temporary which then sets it back
in the destructor is an example of very tricky interaction and IMHO bad
code.
 
Christian
Tim Rentsch <txr@alumni.caltech.edu>: Jul 01 12:29AM -0700


> Has the conditional turned into a somewhat incomprehensible
> monstrosity already in 2, or is it the use of a data member, as in 3,
> that makes their eyes glaze over?
 
Let me offer some purely personal reactions (not just on the
above question but on the thread topic generally).
 
First I think the idea that ?: is somehow "too difficult" (for
some unspecified set of programmers) is overblown. If someone
can't understand the ?: operator inside of 15 minutes they
shouldn't be programming at all, full stop.
 
Second, the trick with doing a member access probably deserves
a comment, but nothing more than that.
 
Third, ditto the first remark, for the comma operator. I don't
see anything wrong with the usage of either ?: or the comma
operator in the original code.
 
Fourth, I didn't know the rule about lifetime of temporary
objects but it doesn't surprise me either. Let me pretend that I
was thoroughly familiar with that rule when reading the code.
 
Now, despite all the foregoing, I still have a funny reaction to
the original expression overall. There are several reasons that
might contribute to this feeling. One, it's unusual to see an
object constructed conditionally - normally it's either there or
it isn't. Two, even knowing the rules for the comma operator and
temporary object lifetime, it's surprising to discover how they
interact here; I might say that part of my brain "knows" that
when control gets to a comma operator, the left-hand operand
expression is "done". Three, I can't escape the feeling that
somehow the construction is "sneaky", or that it expresses what
is meant in a less direct way than it could. I'm reminded of how
I felt the first time I saw Duff's device - I understood all the
pieces just fine, but the effect of the combination was still
suprising. In the case of Duff's device there was a particular
motivation that offset the surprise factor, and I think that
was a good decision (ie, in the original circumstances). Here I
don't know what the offsetting motivation would be. The various
forces you have mentioned - RAII, factoring, etc - all are worth
observing, but none of them is absolute. I think this is one of
those rare cases where one of the "inviolable" rules needs to be
broken, because not doing that would lead to a worse result.
 
So fwiw, there is my own sense of the situation. Not saying
anyone else should feel the same way, just that this is how
it strikes me.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 01 10:27AM +0200

On 01.07.2018 08:48, Christian Gollwitzer wrote:
> was heavily wondering how the hell can the app::run() access anything
> from these with_stream... objects. The problem is the data flow via side
> effects.
 
This, how the code appears to you, is interesting, because the RAII
side-effect variable general technique that is problematic to you, and
presumably also to the other critics, is idiomatic except that usually
the variable is technically needlessly /named/.
 
This example is from ¹cppreference.com,
 
 
std::lock_guard<std::mutex> guard(g_pages_mutex);
g_pages[url] = result;
 
 
For this use the name "guard" isn't ever used for anything. It just
possibly can produce a warning from the compiler, like hey, you forgot
to use that thing... Which possible warning can be suppressed by writing
 
 
std::lock_guard<std::mutex> guard(g_pages_mutex);
(void) guard;
g_pages[url] = result;
 
 
But better, in my opinion, is to just never introduce that extraneous
misleading not-used-for-anything name in the first place:
 
 
std::lock_guard<std::mutex>{ g_pages_mutex }
, g_pages[url] = result;
 
 
So that's the technical background: it's a cleaned up version, namely,
no unused name, of a very common C++ idiom.
 
* * *
 
A technical alternative to the "data flow via side effects" where cin is
modified, could be to pass an istream reference down the call chain
instead of directly using cin in app::run and lower.
 
But that would be a parameter explicitly propagated down the call chain
just to support the faux text used in the software development.
 
That feels very wrong to me, very Microsoft-ish :(, both because it
would misleadingly communicate to readers of the code that this
generalization was there to support the ordinary purpose of the code,
and because it would add a technically unnecessary cost to every
function in the call chain just to support readability at a top level.
 
 
> It would have been different if it looked like
 
> app::run(args[1] == "--faux-text" ? with_stream() : with_faux());
 
As a general technique that seems to get impractical, adding unnecessary
complication.
 
E.g. here's the earlier cppreference example reworked to use that technique:
 
 
void set_pages_entry(
const std::string& key,
const std::string& value,
const std::lock_guard<std::mutex>& // lets caller pass object
)
{
g_pages[key] = value;
}
 
//...
set_pages_entry( url, result,
std::lock_guard<std::mutex>{g_pages_mutex} );
 
 
Of course the mutex locking can and probably should be moved into that
function, given that one wants to keep the function, like this:
 
 
void set_pages_entry(
const std::string& key,
const std::string& value
)
{
std::lock_guard<std::mutex>{ g_pages_mutex }
, g_pages[key] = value;
}
 
//...
set_pages_entry( url, result );
 
 
 
But now there's something eerily familiar about the function body code...
 
By adopting the suggested pass-it-in-a-function-call technique, and
cleaning up the resulting code, we got back where we started.
 
Except that now there's an added function.
 
 
 
> app App;
> app.setStream(args[1] == "--faux-text" ? with_stream() : with_faux())
> app.run();
 
Not sure what you mean here. Instead of having the global state that
affects `cin` in `cin`, have the global state that affects `cin` in an
object called `app`?
 
 
> Modifying a global state from within a temporary which then sets it back
> in the destructor is an example of very tricky interaction and IMHO bad
> code.
 
Well, /that part/ is idiomatic, except for using a technically
unnecessary name that might produce a warning about being unused.
 
I never understood why such name is always used.
 
But now I understand it some, that the name, or perhaps the separation
into distinct statements that it allows, aids in code comprehension?
 
 
Cheers!,
 
- Alf
 
Notes:
¹ <url: https://en.cppreference.com/w/cpp/thread/mutex#Example>
Manfred <noname@invalid.add>: Jul 01 01:35PM +0200

On 7/1/2018 10:27 AM, Alf P. Steinbach wrote:
>         , g_pages[url] = result;
 
> So that's the technical background: it's a cleaned up version, namely,
> no unused name, of a very common C++ idiom.
 
The intent is clear, and the idiomatic background is clear too.
Still I have a few considerations:
 
Your approach is heavily based on the lifetime of a temporary, which,
being unnamed, is hidden from the explicit flow of the code.
In common C++ programming, the lifetime of temporaries is typically
handled as something "the compiler will take care of", and the
programmer typically wants to care little more than the upper limit of
its lifetime span: the terminating ; of the statement.
 
In this case (the original one, not the lock guard) you are effectively
defining an execution context for the app. This is worth a name, IMO.
 
Moreover, the whole context object (With_faux_text or
With_stream_detection) is hanging on the obscure '_' member - and one
has to think about the guarantee that this actually ensures that the
whole object is kept alive.
 
In short, your proposal works, but instead of /using/ the syntax to
express an intent (which is what programmers do), it constrains the
coding of the intent within a chosen syntax.
 
* * *
 
That said, your recalling of the lock guard raises a different
consideration - when writing:
 
std::lock_guard<std::mutex> guard(g_pages_mutex);
 
what I still find annoying is that you may forget to name the thing
(because you don't use the name afterwards), and the resulting statement:
 
std::lock_guard<std::mutex>(g_pages_mutex);
 
will compile, but be ineffective - most annoyingly, /silently/
ineffective (unless you have a compiler that can catch this stuff, and
you instruct it to do so).
 
[Microsoft has handled this its way, i.e with an ad-hoc solution
in C# they have a dedicated lock statement which reads:
lock(mutex_object)
{
...
}
]
 
So, I think you actually have a point with respect to the unnecessary
name, but not just because it is /cleaner/ code, but because since it is
unused after declaration, it can be forgotten and lead to a non-trivial
error (non trivial because compilers may miss it).
Wouter Verhelst <w@uter.be>: Jul 01 09:23AM +0200

On 30-06-18 13:17, Bart wrote:
 
> If min/max were operators, so that they could be written as 'a max b',
> perhaps as well as 'max(a,b)', then the following becomes possible:
 
>    a max= b;
 
Which can be written as a = max(a, b); just as well
 
> as well as:
 
>    A[++i] max= lowerlim;
 
A[++i] = max(A[i], b);
 
... and then max just needs to either be a safe macro or an inline function.
 
With gcc, you can make it a safe macro like so:
 
#define max(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ?
_a : _b; })
 
typeof is a gcc extension that evaluates to the type of the expression,
without evaluating the expression (so it has no side effects), except as
necessary to do what it needs to do:
 
#include <stdio.h>
int main(void) {
int i = 0;
char c = 2;
typeof(i++) j = i;
printf("%d %d\n", i, j); // output: 0 0
typeof(++i == 1 ? i : c) c2 = c;
printf("%d %d\n", i, (int)c2); // output: 0 2
}
 
the ({ ...code... }) syntax is also a gcc extension called a "statement
expression", which evaluates to the value of the final expression in the
inner code block.
 
https://gcc.gnu.org/onlinedocs/gcc-8.1.0/gcc/Statement-Exprs.html
 
 
> (And actually, the x64 processor has native MIN and MAX instructions for
> floating point; presumably they were considered useful enough to
> implement in hardware.)
 
I'm sure a decent optimizing compiler will optimize something like a max
function or safe macro implemented with a trinary operator or a simple
if() to that instruction.
Barry Schwarz <schwarzb@dqel.com>: Jul 01 01:54AM -0700


>> as well as:
 
>>    A[++i] max= lowerlim;
 
>A[++i] = max(A[i], b);
 
Unfortunately, this invokes undefined behavior.
 
 
--
Remove del for email
Bart <bc@freeuk.com>: Jul 01 10:08AM +0100

On 01/07/2018 08:23, Wouter Verhelst wrote:
>> perhaps as well as 'max(a,b)', then the following becomes possible:
 
>>    a max= b;
 
> Which can be written as a = max(a, b); just as well
 
Sure. As can 'a += b'.
 
But there must be a reason why such 'assignment operators' (not
'augmented assignment' as I thought they were called) were present even
in early C.
 
 
> I'm sure a decent optimizing compiler will optimize something like a max
> function or safe macro implemented with a trinary operator or a simple
> if() to that instruction.
 
I don't use an optimising compiler. Evaluating 'max(a,b)' when a,b are
ints, and 'max' is a function (not a macro, not even an inline function)
involves executing some 14 instructions, including call, return and
branches [on x64].
 
But when 'max' is an intrinsic operator, then it can be trivially done
in 4 instructions when a and b are int (3 is possible), and 2
instructions when they are floats, none of which are branches.
 
You also get the advantage of overloading via the usual operator
mechanisms, without needing to rely on anything else (safe macros,
overloaded functions etc).
 
 
--
bart
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 01 12:15PM +0200

On 01.07.2018 11:08, Bart wrote:
 
> But there must be a reason why such 'assignment operators' (not
> 'augmented assignment' as I thought they were called) were present even
> in early C.
 
They corresponded directly, and still correspond, to very common
processor instructions, and at that time it was more the programmer's
job, and not the compiler's, to optimize the resulting machine code.
 
Typically an integer add instruction, say, adds to a register, like on
the i8086 (the original IBM PC processor, except for data bus width):
 
add ax, bx ; add the contents of register ax, to bx
 
So in C and C++:
 
ax += bx;
 
Of course, historically that was ten years or so after development of C
started, PC 1981 versus plain C 1971. I think the original C development
was on a PDP-10. I had some limited exposure to the PDP-11, but all I
remember about the assembly language was that it was peppered with @
signs (probably indicating macros), and that the registers were numbered
and memory-mapped. But I'm pretty sure that if the PDP-11 didn't have
add to register, I'd remember that. And so, presumably also the PDP-10.
 
Disclaimer: maybe C development started a year or two later. And maybe
it was a PDP-9, if such a beast existed. Google could probably cough up
the more exact history, but it doesn't matter here.
 
[snip]
 
 
Cheers!,
 
- Alf
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 01 12:17PM +0200

On 01.07.2018 12:15, Alf P. Steinbach wrote:
> Typically an integer add instruction, say, adds to a register, like on
> the i8086 (the original IBM PC processor, except for data bus width):
 
>     add ax, bx    ; add the contents of register ax, to bx
 
"of register bx, to ax"
 
 
> So in C and C++:
 
>     ax += bx;
> [snip]
 
 
Sorry,
 
- Alf
Ben Bacarisse <ben.usenet@bsb.me.uk>: Jul 01 12:20PM +0100


> On 01.07.2018 11:08, Bart wrote:
<snip>
 
> They corresponded directly, and still correspond, to very common
> processor instructions, and at that time it was more the programmer's
> job, and not the compiler's, to optimize the resulting machine code.
 
I think that is an unlikely explanation. First, they came into C from
Algol68 via B, and Algol68 never had any intention of providing
operators for the purpose of helping the programmer optimise code!
Secondly, there never was a B compiler in the traditional sense of one
that generated machine instructions.
 
However, there's a grain of truth here. B was implemented as "threaded
code" where each operation is translated into a jump to the code that
performs the appropriate action. There was no possibility of doing any
optimisation in 8K (on a PDP-7) but a =+ b was bound to be more
efficient that a = a + b simply because it could be translated to single
jump.
 
> I think the original C development was on a PDP-10.
 
Even "New B" development was done on the PDP-11 and anything that can
reasonably be called C certainly was.
 
> Disclaimer: maybe C development started a year or two later. And maybe
> it was a PDP-9, if such a beast existed.
 
B was born on the PDP-7 and C on the PDP-11.
 
> Google could probably cough
> up the more exact history, but it doesn't matter here.
 
True, but it's nice to keep the history straight.
 
--
Ben.
Bart <bc@freeuk.com>: Jul 01 12:20PM +0100

On 01/07/2018 11:15, Alf P. Steinbach wrote:
 
> They corresponded directly, and still correspond, to very common
> processor instructions, and at that time it was more the programmer's
> job, and not the compiler's, to optimize the resulting machine code.
 
 
Sometimes they will correspond to hardware instructions, other times
they don't (eg. floating point on modern x86).
 
Such assignments were of part of Algol68 (created around 1968 I
believe), and there were doubtless earlier precedents.
 
They are useful to better express intent, and make it easier for a
compiler to generate code (otherwise they have to decide where a[f(x)].b
= a[f(x)].b + 1 is the same thing as a[f(x)].b += 1; it's a lot easier
if the programmer just writes the latter).
 
They can also indicate something subtly different from A = A+1, as in my
more complex example, where f(x) with possible side-effects might be
called once or twice.
 
Also in this example (not from C):
 
s = s + "A"
 
This takes a string s, creates a new string with "A" appended, then
assigns back into s, destroying the original. Lots of string processing
going on.
 
But write it like this:
 
s += "A"
 
and now it can be taken to mean in-place append. Given adequate
capacity, which is usually the case, this now writes adds one byte onto
the end of s, and updates its length.
 
> signs (probably indicating macros), and that the registers were numbered
> and memory-mapped. But I'm pretty sure that if the PDP-11 didn't have
> add to register, I'd remember that. And so, presumably also the PDP-10.
 
I don't think C was developed for PDP10, not at first anyway. But as I
said, augmented assignment was not just limited to C, it has other
benefits that just mapping neatly to hardware instructions.
 
 
--
bart
Borneq <borneq@antyspam.hidden.pl>: Jul 01 10:23AM +0200

I have small project which uses LLVM.
LLVM under Linux has 134 *.a files counting 5 gigabytes.
I can't add everything to CodeBlocks project.
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Jun 30 07:26PM -0400

On 06/30/2018 07:02 PM, Chris M. Thomasson wrote:
 
> struct parts p = { { 12 }, { 34 } };
 
> p.p1.b = 42;
> ____________________________
 
I considered that solution. It has a few fundamental flaws. Namely:
 
You have to reference struct components with additional naming steps,
and even if you make them anonymous you still can't have members which
overlap from one struct into the next.
 
> ;^)
 
:-(
 
--
Rick C. Hodgin
Bart <bc@freeuk.com>: Jul 01 12:55AM +0100

On 30/06/2018 23:45, Rick C. Hodgin wrote:
 
> I devised it. And it's not ugly or confusing. With syntax highlighting
> applied there are color bars which differentiate each grouping, and the
> section headers are hidden.
 
Effectively you're taking the elements of a struct, ignoring any
existing nested structure, and treating it as a mixed-type array, with
sections defining random slices of that array.
 
Since you can't really have a mixed-type array, your are actually
superimposing multiple different structs - non-nested ones - on top of
arbitrary portions of a regular struct.
 
It sounds interesting but I'm struggling to think of a use which is not
better handled by redesigning the original struct to better suit the
requirements.
 
> is criticized by you in your replies? It's a bad idea as I propose it,
> or it doesn't add enough value to be useful, or its just clutters up
> something, etc.?
 
Maybe it's just me but I have a really hard time understanding the point
of your proposals. I think new features should be kept to a minimum and
the ones that are added should be obviously useful without needing to
scratch your head wondering under what circumstances they might ever be
used.
 
> create one. But I do have a need for this ability, and it's not that
> difficult to add to the compiler, and I can see it have great utility
> when you stop and give the potential uses some thought.
 
If I really wanted something like that, I would probably implement it as
something like a slice. That is, a span from field .a to field .b, where
a, b and the fields in-between can all be different types.
 
The declaration of the struct needs no extra annotations; and the same
struct can be sliced in different ways by different programs, if it is
shared. In fact, the slice can be applied to a struct declared in a
third party header.
 
(As for syntax, that would need some thought, but could be as simple as
X.(a,b) where X is a struct expression, and a,b are field names.)
 
--
bart
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Jun 30 05:00PM -0700

On 6/30/2018 4:26 PM, Rick C. Hodgin wrote:
>> ____________________________
 
> I considered that solution. It has a few fundamental flaws. Namely:
 
> You have to reference struct components with additional naming steps,
 
Consistent with C.
 
 
> and even if you make them anonymous you still can't have members which
> overlap from one struct into the next.
 
Are you really that worried about the naming steps:
 
p.p1.b ?
 
Like trying to spread some sort of syntactic sugar all over the place?
What about the ants?
 
;^)
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Jul 01 12:06AM -0400

On 06/30/2018 07:55 PM, Bart wrote:
 
> It sounds interesting but I'm struggling to think of a use which is not
> better handled by redesigning the original struct to better suit the
> requirements.
 
It allows you to send only portions of your parent object to external
things, making only those portions visible to it.
 
> the ones that are added should be obviously useful without needing to
> scratch your head wondering under what circumstances they might ever be
> used.
 
Pretty much every idea I've had has occurred to me while coding. I've
had some need to do something, and the tool wouldn't allow it to be
done, so I've gone to define it.
 
 
> If I really wanted something like that, I would probably implement it as
> something like a slice. That is, a span from field .a to field .b, where
> a, b and the fields in-between can all be different types.
 
The section definitions I stated above could work with slices. You
could append single lines or multiple separate blocks.
 
It basically creates a protocol to allow sub-portions of the encap-
sulating object to be exposed externally.
 
 
--
Rick C. Hodgin
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Jul 01 12:08AM -0400

On 06/30/2018 08:00 PM, Chris M. Thomasson wrote:
>> overlap from one struct into the next.
 
> Are you really that worried about the naming steps:
> p.p1.b ?
 
Worried? No. It's just ridiculous to force such a thing on people.
 
--
Rick C. Hodgin
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Jun 30 09:58PM -0700

On 6/30/2018 9:08 PM, Rick C. Hodgin wrote:
 
>> Are you really that worried about the naming steps:
>> p.p1.b ?
 
> Worried? No. It's just ridiculous to force such a thing on people.
 
Why is that so "ridiculous"? It sure allows one to know exactly what
they are referring to; It sure shaves off a lot of ambiguity. ;^)
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Jun 30 09:59PM -0700

On 6/30/2018 9:06 PM, Rick C. Hodgin wrote:
> could append single lines or multiple separate blocks.
 
> It basically creates a protocol to allow sub-portions of the encap-
> sulating object to be exposed externally.
 
Okay, but it seems like adding some extra, perhaps unnecessary sugar to
the mix. Might have to see a dentist.
 
 
 
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Jul 01 12:48AM -0700

On 6/30/2018 9:59 PM, Chris M. Thomasson wrote:
>> sulating object to be exposed externally.
 
> Okay, but it seems like adding some extra, perhaps unnecessary sugar to
> the mix. Might have to see a dentist.
 
Perhaps it can be handy from time to time. Need to think on it.
 
 
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Jul 01 12:54AM -0700

On 7/1/2018 12:48 AM, Chris M. Thomasson wrote:
 
>> Okay, but it seems like adding some extra, perhaps unnecessary sugar
>> to the mix. Might have to see a dentist.
 
> Perhaps it can be handy from time to time. Need to think on it.
 
You would have to explicitly document this feature in the CAlive
archives. And perhaps try to think of giving out some simple highly
experimental online compiler examples on how to use it in a very
experimental space.
 
Think producing an interactive tutorial, to go along with your highly
adaptive, user friendly and extraordinarily integrated debugger! I have
to admit walking through code in a GUI debugger before.... MSVC was
always a nice one, indeed. :^)
 
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Jul 01 12:45AM -0700

On 6/27/2018 2:37 PM, Chris M. Thomasson wrote:
 
>> Nope, the tools should be updated to cope with the new language rules.
 
>> However, auto return type should be avoided in API-s
 
> Agreed.
 
The return value of a function in an API exported from a shared lib, say
DLL or .so, must be concrete? This is what I am talking about wrt API.
Not a C++ header wrt API that can contain all sorts of fancy things...
 
;^)
 
 
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: