Tuesday, February 28, 2017

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

Steve Keller <keller@no.invalid>: Feb 24 06:52PM +0100

For a simple interpreter I wrote a class
 
class Stmt {
public:
virtual void exec() const = 0;
...
};
 
and several statement classes derived from that. In these classes I
have a number of occurrences of code like the following:
 
class FooStmt : public Stmt {
Stmt *s;
public:
virtual void exec() const {
if (s)
s->exec();
}
};
 
Therefore, I added a wrapper
 
void exec(const Stmt *s) {
if (s)
s->exec();
}
 
However, in order to be able to call exec(const Stmt *) from inside
FooStmt, I either need to
 
a) make this wrapper a static member function of class Stmt
 
b) if the wrapper is outside of class Stmt, I have to call it using
 
::exec(s)
 
instead of only exec(s).
 
c) rename the wrapper to something different than exec.
 
It seems the compiler, when looking for an exec(const Stmt *)
function, first looks for any exec(...) function in FooStmt and if it
finds one (in this case the exec() member function without parameters)
it does not continue to look for a matching exec(const Stmt *) outside
of FooStmt. But why does is behave that way?
 
I don't like any of these solutions because a) makes the wrapper
visible in the header file and b) and c) look cumbersome.
 
Are there other suggestions?
 
Steve
"Adam C. Emerson" <azure@fox.blue>: Feb 24 08:13PM

> s->exec();
> }
> };
[snip]
 
This design looks very strange to me. Why do you both inherit from
Stmt and include a pointer to Stmt?
Cholo Lennon <chololennon@hotmail.com>: Feb 24 05:41PM -0300

On 24/02/17 17:13, Adam C. Emerson wrote:
> [snip]
 
> This design looks very strange to me. Why do you both inherit from
> Stmt and include a pointer to Stmt?
 
Because, at 1st glance, it seems like the OP is using the decorator pattern.
 
--
Cholo Lennon
Bs.As.
ARG
Steve Keller <keller@no.invalid>: Feb 25 01:10AM +0100

> [snip]
 
> This design looks very strange to me. Why do you both inherit from
> Stmt and include a pointer to Stmt?
 
Actually, there is no FooStmt but WhileStmt, IfStmt. ForStmt, etc.
which *are* statements and some contain other statements. There's
also an abstract base class Expr with a number of subclasses, and my
statements look like this
 
class WhileStmt : public Stmt {
Expr *cond;
Stmt *body;
public:
...
};
class IfStmt : public Stmt {
Expr *cond;
Stmt *s1, *s2;
public:
...
};
class ForStmt : public Stmt {
Expr *init, *cond, *iter;
Stmt *body;
public:
...
};
class ExprStmt : public Stmt {
Expr *expr;
public:
...
};
 
I think that is quite straight forward and natural.
 
Steve
Paavo Helde <myfirstname@osa.pri.ee>: Feb 25 03:25AM +0200

On 25.02.2017 2:10, Steve Keller wrote:
> doesn't match the definition of FooStmt::exec() I wouldn't count this
> as a match and continue matching in a wider scope and would find the
> actually matching global exec(const Stmt *).
 
Yes, this might seem like a good idea, but over the years I have learned
the hard way that trying to be too clever is about the worst thing a
language can do. The reason is that if the language is too clever then
the programmer is not able any more to figure out how it works and thus
it loses control over how to achieve that it wants.
 
C++ already has function overloading, Koenig lookup and other things
where it has arguably gone too clever, there is no need to make it even
more "cleverer".
 
> also, although I don't have the same problem there. What I dislike a
> little is that in s.exec() the member s doesn't really look like a
> pointer anymore.
 
You can make it look like s->exec() with some more effort, though by
some reason I suspect you are wasting your pedantry in wrong areas.
 
There are no abstract ideals to which your code should conform.
 
Instead, programming is an engineering discipline, meaning everything
serves a purpose. Consistency of the code and markup is needed only for
the maintainer programmer (including yourself 6 months ahead) to
understand the program so he can easily maintain or refactor it. In this
sense, writing some decent unit tests is probably much more helpful than
a minor stylistic consistency.
Paavo Helde <myfirstname@osa.pri.ee>: Feb 23 11:10AM +0200

On 23.02.2017 6:35, Christiano wrote:
> inside a function and then passing it through return forces the calling
> function to make a copy of an object, if that object is large it can
> make everything inefficient.
 
1) A 'date' does not look like it could be large.
 
2) Compilers have been optimizing this kind of stuff for many years
(according to Wikipedia RVO was invented in 1991).
 
3) Since C++11, we also have rvalue references and move constructors &
assignments, which work best with temporaries like function return
values (otherwise you will need to pepper the code with unwanted noise
like std::move()).
 
4) If you want to make sure that no copies are made behind the curtains
you can mark the copy constructor and assignment deleted for the class
and rely on the move ctor/assignment instead. This coincidentally means
you should make use more of function return values, not less.
 
5) As you certainly know, premature optimization is the root of all
evil. Before reducing the readability and maintainability of your code
by doing manual "optimizations" which you *believe* should make the code
faster, take some time to actually *measure* it and see if your beliefs
have any ground.
ram@zedat.fu-berlin.de (Stefan Ram): Feb 25 04:07AM

>N_TIMES( n )
 
Maybe a symbolic interpretation helps to understand this:
 
N_TIMES( m )
 
N_TIMES_AUX( MM_CONCAT( i_, __COUNTER__ ), MM_CONCAT( i_, __COUNTER__ ), m )
 
N_TIMES_AUX( MM_CONCAT_( i_, 0 ), MM_CONCAT_( i_, 1 ), m )
 
N_TIMES_AUX( MM_CONCAT__( i_, 0 ), MM_CONCAT__( i_, 1 ), m )
 
N_TIMES_AUX( i_ ## 0, i_ ## 1, m )
 
N_TIMES_AUX( i_0, i_1, m )
 
N_TIMES_AUX( i_0, i_1, m )
 
N_TIMES_AUX( i_0, i_1, m )
 
Index i_0 = 0, i_1 = m; i_0 < i_1; ++i_0
 
Now what would happen if we would remove one MM_CONCAT level?
 
#define MM_CONCAT_( a, b ) a ## b
#define MM_CONCAT( a, b ) MM_CONCAT_( a, b )
 
N_TIMES( m )
 
N_TIMES_AUX( MM_CONCAT( i_, __COUNTER__ ), MM_CONCAT( i_, __COUNTER__ ), m )
 
N_TIMES_AUX( MM_CONCAT_( i_, 0 ), MM_CONCAT_( i_, 1 ), m )
 
N_TIMES_AUX( i_ ## 0, i_ ## 1, m )
 
N_TIMES_AUX( i_0, i_1, m )
 
N_TIMES_AUX( i_0, i_1, m )
 
Index i_0 = 0, i_1 = m; i_0 < i_1; ++i_0
 
Same result!
 
Let's remove another level!
 
#define MM_CONCAT( a, b ) a ## b
 
N_TIMES( m )
 
N_TIMES_AUX( MM_CONCAT( i_, __COUNTER__ ), MM_CONCAT( i_, __COUNTER__ ), m )
 
N_TIMES_AUX( i_ ## __COUNTER__, i_ ## __COUNTER__, m )
 
N_TIMES_AUX( i___COUNTER__, i___COUNTER__, m )
 
Index i___COUNTER__ = 0, i___COUNTER__ = m; i___COUNTER__ < i___COUNTER__; ++i___COUNTER__
 
That would be too much. So you can remove one level of
MM_CONCAT, but not more, i.e., the following still works:
 
#define MM_CONCAT_( a, b ) a ## b
#define MM_CONCAT( a, b ) MM_CONCAT_( a, b )
#define N_TIMES_AUX( i, n, expr ) Index i = 0, n = expr; i < n; ++i
#define N_TIMES( n ) N_TIMES_AUX( MM_CONCAT( i_, __COUNTER__ ), MM_CONCAT( i_, __COUNTER__ ), n )
 
Disclaimer: I, too, do /not/ know the actual C++ standard
rules, I just inferred to above reduction steps from the
behavior of a specific implementation and some guesswork.
ram@zedat.fu-berlin.de (Stefan Ram): Feb 25 04:37AM

>It also occurred to me that I don't know that standard's rules that make
>this case work as unexpected, but makes the code invalid when the `if`
>is replaced with a `while` or `switch`.
 
By »invalid«, you might mean that »seven!« will /not/ be
printed in the case of a »while«. I believe that the
standard requires the »while« to behave like the »if«,
and when »seven!« is not printed, it's an error in the
C++ implementation.
 
A nested »switch«, however, clearly starts a new scope
for case-lables, so it is correct, when »seven!« is not
printed in this case.
ram@zedat.fu-berlin.de (Stefan Ram): Feb 25 05:44PM

>Still, with the compilers disagreeing it would be nice to know what the
>standard says about this.
 
Before I wrote the post that you answer to in the post
quoted above, I /did/ read the section about the switch
statement in the recent draft and tried to incorporate
what I understood from this reading into my post.
 
I assume that you are able to find "switch" in the
table of contents of the version of the standard that
you prefer to use, so that there is no need for me to
actually quote this section here.
 
>trick work. So it seems Visual C++ is right and g++ is buggy, but... :)
 
The bug seems to be in the code for /constant/ values
as conditions. IIRC, the bug disappeared yesterday when
I used a condition that is false only at runtime.
 
IIRC the JLS (Java Language Specification) might even
guarantee that »if( false )...« is removed during
compilation. Let me try this in Java:
 
Main.java
 
public final class Main
{ public static void main( final java.lang.String[] args )
{ switch( 7 )
{ case 6:
if( false )
{ case 7: java.lang.System.out.println( "is 7" ); break; }}}}
 
transcript
 
Main.java:6: error: orphaned case
{ case 7: java.lang.System.out.println( "is 7" ); break; }}}}
^
1 error
 
(same for »if( true )« and »while( true )«)
 
JavaScript:
 
{ switch( 7 )
{ case 6:
while( true )
{ case 7: console.log( "is 7" ); break; }}}
 
SyntaxError: expected expression, got keyword 'case'
 
C sharp:
 
Program.cs
 
public static class Program
{
public static void Main()
{ switch( 7 )
{ case 6:
if( false )
{ case 7: global::System.Console.WriteLine( "is 7" ); break; }}}}
 
transcript
 
Program.cs(7,9): error CS1513: } expected
ram@zedat.fu-berlin.de (Stefan Ram): Feb 25 11:09PM

>The posted article is OK, but your newsreader doesn't recognize the
>flowed format specified in the content type header:
 
Ok, thanks! Now I remember that we might have had this
discussion before. Unfortunately, in the meantime, I
forgot about the »format=flowed« content type.
 
>I believe all modern common newsreaders support flowed format, so you
>have a large number to choose from, including just using Thunderbird, as
>I do. ;-)
 
Yes, I am not using one of the modern common newsreaders.
 
Now I hope that I will be able to remember that »format=flowed«
is not displayed as intended in my newsreader.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Feb 24 12:41AM +0100

> $var instead of auto? Why don't you like the auto keyword?
 
I don't /dislike/ `auto`. But `auto` has many different meanings, and
that makes it
 
• hard to search for e.g. variable declarations as opposed to constant
or reference declarations,
 
• hard to see at a glance what kind of declaration (such as variable or
constant, as in the array example below) a declaration is,
 
• hard to see what type a declaration is about, and
 
• I believe, difficult to learn to use correctly for a novice.
 
These are problems that are somewhat alleviated by the $ pseudo-keywords.
 
There are also problems, some mentioned below, that are irrelevant for
the use or not of pseudo-keywords, at least as long as they're macros
and not more real keywords supported by compiler extension. I think it's
easier now to do compiler extensions, with clang's support machinery.
But the last time I tried my hand at that, with gcc (for an idea about
exception handling), I found that gcc had a really complex structure
expressed in the apparently lowest possible level K&R C...
 
• • •
 
Regarding the claim of hard to see type, consider
 
auto s = "Blah";
 
Until I learned this as a special case (that didn't take long, but
until) I thought this would deduce `s` as `char const[5]`, which is
non-assignable and with length. But it deduces `s` as `char const*`.
Which is not even a constant, so one can, perhaps inadvertently, do
 
s = "Oh!";
 
Well, then perhaps change the declaration to
 
auto s[] = "Blah"; // ?
 
But contrary to what I think is a natural expectation, one just can't
use `auto` for an array item type: that won't compile.
 
The /technically/ correct way when one desires `s` as an immutable array
with length information retained, as the initializer, is to write
 
auto& s = "Blah";
 
But I wouldn't do that because it just obscures the desired result.
 
With the pseudo-keywords one can, however, write quite naturally
 
$let s = "Blah"; // `s` is const, decayed to pointer
$var s = "Blah"; // `s` is variable, decayed to pointer
$name s = "Blah"; // `s` is `char const[5]`
 
where
 
• $let → auto const, always yielding just a constant /value/;
 
• $var → auto, always yielding a mutable /variable/; and
 
• $name → auto&, always yielding just an /alias/.
 
Still lacking is a way to express
 
decay_t<decltype( *"Blah" )> s[] = "Blah";
 
which yields a mutable array, `char[5]`. A macro for this would get
/too/ ugly not just because it would have to take the initializer as
argument, but because that initializer could easily contain a comma or
two, which would be interpreted as macro argument separators. Well, a
variadic macro would be able to handle that, but it would still be ugly.
 
• • •
 
As an example of a problem that as far as I can see is not generally
solvable with keywords, consider the following code:
 
template< class Some_type >
using ref_ = Some_type&;
 
template< class Stream >
auto int_from( ref_<Stream> stream )
-> int
{
int result;
stream >> result;
if( stream.fail() ) { abort(); }
return result;
}
 
auto input_int( ref_<const wstring> prompt )
-> int
{
wcout << prompt;
return int_from( wcin ); // <--- Deducing the type Stream.
}
 
That works fine.
 
But the second declaration here does not work fine:
 
void foo()
{
auto& yep = wcin;
ref_<auto> nope = wcin; // <--- Uh oh.
 
(void) yep; (void) nope;
}
 
The problem here isn't the reference, which is just one specific use
case, it's the use of `auto` as a template (alias) argument.
 
The good old general template argument type deduction can see right
through that little template alias, as in the `ref_<Stream>`, but `auto`
just doesn't cut it.
 
 
> Why do you prefer obfuscation to idiomatic C++? What you are doing
> try to make C++ code look like code from other inferior languages is
> really egregious.
 
Well, those are emotional reactions.
 
I don't share them. :)
 
Actually I felt happy being able to express how I think about things
(just also slightly annoyed at having to use evil macros etc.).
 
For re the inferior languages, I think that to use C++ in a good way one
must have a clear picture of what /hypothetical language constructs/,
usually very much like constructs from other languages that one has
used, one is trying to implement with one's C++ code.
 
For example, to me, header and implementation files, and the whole thing
with include guards etc., implements modules, like Modula-2 MODULE or
Pascal UNIT or Ada PACKAGE. I haven't really used Ada but I've read some
books about it. And for example, to me, my `i_up_to` for a range-based
loop, implements in an imperfect but practically useful way, Python 2.7
`xrange` or Python 3.x `range`. And correspondingly, e.g. the $let
pseudo keyword in the expressive dialect implements in a very restricted
and awkward, but IMHO still very practically useful, way, a logical
`let` from a functional language or maths.
 
 
Cheers!,
 
- Alf
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Feb 25 10:16PM

On 23/02/2017 17:57, Mr Flibble wrote:
 
> All this $let_mutable and such bollocks makes your code harder to grok
> than standard C++ so I have no interest in examining it and therefore
> answering your questions about it.
 
Also use of dollar sign ($) in identifiers is implementation defined and
thus non-portable and to be avoided.
 
/Flibble
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Feb 22 12:06AM

On 21/02/2017 23:58, Rick C. Hodgin wrote:
[snip]
 
> are to teach those who have an ear to hear the truth about their
> sin, of condemnation for sin, and their need of forgiveness by
> Jesus Christ.
 
Jesus Christ never existed; he was a fictional invention of the latter
half of the first century when the gospels were being written.
 
[snip]
 
/Flibble
Real Troll <real.troll@trolls.com>: Feb 21 06:36PM -0400

Can we just kill this thread now as it has reached its shelf life.
 
Please kill-file that one person who keeps posting non C++ stuff and the
problem is solved once and for all.
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Feb 21 07:10PM

On 21/02/2017 15:21, Rick C. Hodgin wrote:
 
> It's a very common practice and ploy by the enemy to get people to come
> to summary conclusions on things based on partial evidence. It's very
> easy (and natural in our flesh) to mock those things we do not understand.
 
It is you that lacks understanding; the understanding that the god you
follow doesn't exist. I am not sure if this lack of understanding is
just deliberately obtuse fucktardary or you are genuinely that stupid.
 
You are entitled to your beliefs just as we are entitled to ours; stop
trying to trample over OUR beliefs: this is not the correct forum for
proselytizing.
 
/Flibble
red floyd <no.spam@its.invalid>: Feb 25 09:37AM -0800

> address from god knows where.
> What is dl_main? Is it when the loader finally jumps to the start
> of the main program?
 
This is not a C++ language question. Please ask in a Linux forum
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Feb 25 11:36PM +0100

On 25.02.2017 19:10, Stefan Ram wrote:
 
> o use a Newsreader that will not break long lines or
 
> o to limit the line length so that the lines are not
> wrapped by the Newsreader.
 
The posted article is OK, but your newsreader doesn't recognize the
flowed format specified in the content type header:
 
Content-Type: text/plain; charset=utf-8; format=flowed
 
I.e. you're using a somewhat deficient newsreader.
 
Flowed format was specified in an RFC called "son of"-something.
Essentially it uses a space at the end of each line as a /line
continuation character/, like `\` in C and C++, or `_` in VBScript, or
`^` in the Windows command interpreter. I don't recall how it deals with
a line that originally has a space at the end.
 
Due to the comments in your headers I suspect that the newsreader is a
home-grown one. Please note that no archivers, in particular Google
Groups (formerly Deja news), will read and respect this comment:
 
X-No-Archive-Readme: "X-No-Archive" is only set, because this
prevents some services to mirror the article via the web (HTTP). But
Stefan Ram hereby allows to keep this article within a Usenet archive
server with only NNTP access without any time limitation.
 
Also note that X-No-Archive doesn't prevent servers from archiving
responses that quote all you wrote, and some people tend to quote
everything in what they respond to.
 
• • •
 
I believe all modern common newsreaders support flowed format, so you
have a large number to choose from, including just using Thunderbird, as
I do. ;-)
 
 
Cheers!,
 
- Alf
Ben Bacarisse <ben.usenet@bsb.me.uk>: Feb 25 03:13PM


> I'm not sure, but I think BCPL, which C was based on, supported
> control structures within expressions; at least had curly braces in
> expressions?
 
It has expressions of the form VALOF <block> used like this:
 
LET l = VALOF $(
LET n, x = 0, 1
WHILE x < y DO n, x = n+1, f(x)
RESULTIS n
$)
 
In fact, that's how functions that need a block are defined.
 
> Anyway, after C++11 and C++14 we can now do that in C++:
 
Surely an example in pure C++ would have been better? The above in C++
is:
 
int p = [&]{
int n = 0, x = 1;
while (x < y) n++, x=f(x);
return n;
}();
 
There has to be a y and and f in scope in both examples.
 
In cases like this you don't need to capture anything in the lambda --
you can just pass arguments:
 
int l = [](int y, int (*f)(int)) {
int n = 0, x = 1;
while (x < y) n++, x=f(x);
return n;
}(123456789, [](int x){ return x*10; });
 
 
> {
> $let sum = $invoked{ int s{}; for( int i = 1; i <= 8; ++i ) s +=
> i; return s; };
 
I'm guessing this is the thunk being called and that it means:
 
auto sum = [&]{
int s{}; for( int i = 1; i <= 8; ++i ) s += i; return s;
}();
 
> and invokes the specified lambda, producing an expression return value
> via C++14 automatic return type deduction, and that works with MSVC
> 2015. :)
 
Where is the % operator being used? Is that masked by the $xyz stuff or
is it in the header?
 
--
Ben.
Paavo Helde <myfirstname@osa.pri.ee>: Feb 25 10:49AM +0200

On 25.02.2017 9:24, Shiyao Ma wrote:
 
> If so, what part?
 
> http://eel.is/c++draft/temp.spec doesn't seem to force the compiler to generate the code.
 
> I'd afraid this might result a link error.
 
Explicit specialization and explicit instantiation are different things.
Only the latter forces instantiation (aka "code generation" in your terms).
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Feb 25 12:30AM +0100

On 25.02.2017 00:24, Paul wrote:
 
> I noticed this: https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms
 
> However, it seems to be exhaustive, without stressing the more common
> and standard patterns.
 
I haven't clicked it but "More" seems to imply a separate original list.
 
Cheers & hth.,
 
- Alf
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Feb 25 12:28AM +0100

On 24.02.2017 23:59, Öö Tiib wrote:
> Most programs written nowadays are multi-threaded and so CoW
> is not too good idea most of the time.
 
Uhm, thread safety is an orthogonal issue. Adding illusory thread safety
to a string class is going to cost, no matter the internal implementation.
 
I write "illusory" because if one shares a mutable string object between
threads, it would be impractical to lock down the object any time its
`operator[]` returns a reference that possibly could be stored by the
thread and used to modify the string at arbitrary times.
 
The standard library's approach of most classes being thread-agnostic is
fine, I think. It's the responsibility of the code that uses those
classes, to ensure thread safe operation. E.g. by simply not sharing
mutable objects between threads.
 
 
Cheers!,
 
- Alf (opinionated, for the occasion)
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Feb 25 03:22AM +0100

My original N_TIMES macro, called $n_times, used a range based `for`
loop. But g++ warned about the loop control variable being unused, and I
found no way to shut it up in code (only way was to turn off that
warning in the g++ invocation). So I'm thinking of using this scheme:
 
 
#include <iostream>
#include <stddef.h>
using namespace std;
 
using Size = ptrdiff_t;
using Index = Size;
 
#define MM_CONCAT__( a, b ) a ## b
#define MM_CONCAT_( a, b ) MM_CONCAT__( a, b )
#define MM_CONCAT( a, b ) MM_CONCAT_( a, b )
 
#define N_TIMES_AUX( i, n, expr ) Index i = 0, n = expr; i < n; ++i
#define N_TIMES( n ) N_TIMES_AUX( MM_CONCAT( i_, __COUNTER__ ),
MM_CONCAT( i_, __COUNTER__ ), n )
 
auto main() -> int
{
int const n = 7;
for( N_TIMES( n ) )
{
cout << "! ";
}
cout << endl;
}
 
 
Here __COUNTER__ is a language extension supported by Visual C++, g++
and clang, and probably far more compilers. Along with the other
language extensions I use (#pragma once, #pragma push, #pragma pop, $ in
identifiers) it's widely supported but not standard, while all sorts of
never-seen-in-the-wild things are being standardized. Hrmf. Innovating
committee. I aim just for the supporting compilers.
 
Anyway, even though I just wrote this code, and e.g. applied the
concatenation trick out of some acquired instinct for that, I don't
understand the details of how it avoids the actual macro argument `n`,
given in `main`, being replaced with the value of the formal macro
argument `n` i N_TIMES_AUX. It works but I don't know how...
 
So, my attempt at breaking it failed, which I'm happy about. Also, that
I identified a big hole in my understanding, that I could ask about. But
is there still some way to break this code?
 
 
Cheers!
 
- Alf
Ian Collins <ian-news@hotmail.com>: Feb 25 10:48AM +1300

On 02/25/17 09:49 AM, Paul wrote:
> Here is some basic pimpl code below:
> I don't understand why this is legal. It seems that class widget{..}
> defines widget as a base class.
 
Where?
 
> And then class widget is then redefined as a class privately inheriting
> from impl.
 
Where?
 
> Why isn't widget being illegally defined twice?
> Also, can someone explain pimpl to me or direct me to a good explanation?
 
I think you need to explain where your conclusions (above) came from,
the code does not support them.
 
> class widget {
 
No base class...
 
> private:
> class impl;
> unique_ptr<impl> pimpl;
 
Contains a nested impl class, no inheritance.
 
--
Ian
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Feb 25 01:59PM +0100

Macro-Magic (MM) is a header-only library with a macro MM_APPLY to
invoke a specified macro on each of up to 21 arguments. There's also
MM_APPLY_WITH_FIXED_ARG to pass a specified fixed first argument to the
invoked macro, and there's MM_NARGS to count the number of arguments
passed to a variadic macro. And MM_CAT to concatenate with expansion.
 
GitHub repository:
<url: https://github.com/alf-p-steinbach/Macro-Magic/>
 
This is pretty old code, from at least back in 2013 or perhaps years
earlier than that, based on an original __VA_NARG__ macro by Laurent
Deniau that he posted on 17 January 2006 to [comp.std.c].
 
<url:
https://groups.google.com/forum/?fromgroups=#!topic/comp.std.c/d-6Mj5Lko_s>
 
I've modified it to work with Visual C++.
 
I see now that I posted it on GitHub that I forgot to add a license, but
it's Boost license 1.0.
 
 
Cheers, & enjoy!,
 
- Alf (hoping there are not too many bugs: code like this touches on an
area where compilers are generally not standard-conforming!)
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Feb 26 03:29AM

On 26/02/2017 00:07, Alf P. Steinbach wrote:
> ³ Sorry about the limitation to "ascii" here. Implementing portable
> Unicode command line support, which raw C++ `main` doesn't offer for
> systems other than *nix, is much work, and I haven't got to that yet.
 
Use of dollar sign ($) in identifiers is implementation defined as to
whether it works so is unportable and should be avoided.
 
/Flibble
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: