Topic: Proposal for pre-processor
Author: "Trevor L. Jackson, III" <fullmoon@aspi.net>
Date: 2000/07/22 Raw View
Francis Glassborow wrote:
> In article <397582AD.8167786@arexsys.com>, Thierry Grellier
> <t.grellier@arexsys.com> writes
> >The advantage of such a solution is that this preserves the overloading
> >of macro names (even though this isn't accpeted yet I think), and this
> >avoid ambiguities with < > : M(a < b , c > d) one or two parameters ?.
> >The modification to the preprocessor are also quite limited.
>
> FWIW I think your approach leaves something to be desired. If you do
> this sort of thing strictly in your own code and it never goes near
> another programmer (now or in the future) then the resulting problems
> are all yours. However when I want to do this sort of thing I either use
> a scripting language to generate the requisite code or I simply hot key
> my text editor. Both these solutions have the advantage that they are
> simple and generate code that is the same that the compiler sees.
Tell me if I have this straight: You prefer to use an external tool to
replicate code and then tweak each instance manually over using an internal
replication tool that you can parameterize with the tweaks. How is this
simpler?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 2000/07/22 Raw View
In article <3977C0B4.525D92B3@aspi.net>, Trevor L. Jackson, III
<fullmoon@aspi.net> writes
>Tell me if I have this straight: You prefer to use an external tool to
>replicate code and then tweak each instance manually over using an internal
>replication tool that you can parameterize with the tweaks. How is this
>simpler?
Yes, I prefer to use tools that I have honed to my needs rather than
complicated tricks relying on an understanding of the odd behaviour of
the C/C++ preprocessor.
Francis Glassborow Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: 2000/07/23 Raw View
Steve Clamage <stephen.clamage@sun.com> wrote in message
news:397650CA.9237A4DC@sun.com...
> The major problem with macros is that they ignore scope.
I also think a major problem with macros is that they make it very
hard to write programming tools. Even innocent C++ parsers must do a
lot of gymnastics to cope with macros.
Andrei
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Thierry Grellier <t.grellier@arexsys.com>
Date: 2000/07/19 Raw View
Hello,
I don't know to which extent the C++ preprocessor is part of the
language. I know that its usage isn't that much recommanded, but with
some frameworks it is helpful having macros avoiding replication of a
lot of code. This also preserves flexibility in framework evolution :
that allows modifying the framework with minimizing changes on code
based on it.
So yes I use macros, but I'm limited with the preprocessor variables
delimitation. Here is a dummy example (I know there are some work around
here, but it is just to illustrate). Suppose the framework needs you to
write nearly always the same methods for each new classes :
void C1::method() {
pre();
Body
post();
}
void C2::method() {
pre();
Body
post();
}
...
void C_n::method() {
pre();
Body
post();
}
I will define the follwoing macro :
#define METHOD(Class, Body) \
void Class::method() {\
pre(); \
Body \
post(); \
}
It works fine until a comma is used in Body argument because the
preprocessor which has a limited tokenizer.
METHOD(c1, a = b; if (c < d) f();) ok
METHOD(c2, f(a, b, c)) ok => parenthesis are well managed
METHOD(c2, cout << "f(a, b, c)") ok => quotes are well managed
METHOD(c3, static t[2] = { 0, 1 };) nok => found one more parameter
because {} are not considered as parenthesis
METHOD(c4, T<T1, 3> v; v->method();) nok => found one more parameter
because <> are not considered as parenthesis
So here is a suggested solution :
Instead of adding {} and <> as parenthesis, one may think of dedicating
some tokens to help finding the boundaries of a parameter (# for example
so far it is already a prepro reserved token). They act like
parenthesis, but are not expanded.
METHOD(c4, #T<T1, 3> v; v->method();#)
METHOD(c3, #static t[2] = { 0, 1 };#)
The advantage of such a solution is that this preserves the overloading
of macro names (even though this isn't accpeted yet I think), and this
avoid ambiguities with < > : M(a < b , c > d) one or two parameters ?.
The modification to the preprocessor are also quite limited.
Does something like this already exist ?
regards,
--
Thierry Grellier (mailto:t.grellier@arexsys.com)
R&D, Engineer
http://www.arexsys.com
tel : +33 476 18 1717 - Fax : +33 (0) 476 61 9393
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Xazziri" <xazziri@gmx.net>
Date: 2000/07/20 Raw View
Thierry Grellier <t.grellier@arexsys.com> wrote in message
news:397582AD.8167786@arexsys.com...
> I don't know to which extent the C++ preprocessor is part of the
> language. I know that its usage isn't that much recommanded, but with
> some frameworks it is helpful having macros avoiding replication of a
> lot of code. This also preserves flexibility in framework evolution :
> that allows modifying the framework with minimizing changes on code
> based on it.
>
> So yes I use macros, but I'm limited with the preprocessor variables
> delimitation. Here is a dummy example (I know there are some work around
> here, but it is just to illustrate). Suppose the framework needs you to
> write nearly always the same methods for each new classes :
>
> void C1::method() {
> pre();
> Body
> post();
> }
>
> void C2::method() {
> pre();
> Body
> post();
> }
>
> ...
>
If it does, the framework is flawed. It may be a dummy example, but if you
admit that there are workarounds, why do you propose this example as an
argument for preprocessor expansion? In this particular case, you can use a
combination of a nonvirtual and several virtual functions (known as the
template method pattern), as follows:
class C_base
{
public:
void method();
protected:
virtual void overridable_method();
};
void C_base::method()
{
pre();
overridable_method();
post();
};
class C1 : public C_base
{
protected:
virtual void overridable_method();
};
This is a lot safer and cleaner than macros. It also eliminates the need for
programmers to look up and decode the exact effects of a macro, which are
not obvious in some cases. Similar arguments can be held for almost every
other use of a macro - there is almost always a macro-free alternative.
<snip>
> So here is a suggested solution :
> Instead of adding {} and <> as parenthesis, one may think of dedicating
> some tokens to help finding the boundaries of a parameter (# for example
> so far it is already a prepro reserved token). They act like
> parenthesis, but are not expanded.
> METHOD(c4, #T<T1, 3> v; v->method();#)
> METHOD(c3, #static t[2] = { 0, 1 };#)
>
<snip>
I believe expansion of the preprocessor should not be encouraged. Most uses
of the preprocessor have been superseded by language constructs that are
superior in both type safety and absence of side-effects. They are also
uniformly readable, contrary to macro constructs, which have to be
considered separately in every case. Expanding the preprocessor even more
would eventually create a rift between people using templates, inline
functions and all the other things meant to decrease preprocessor use, and
people using the nifty features of the preprocessor.
The preprocessor is a relic. It has some limited use for issues that cannot
be handled by language constructs alone, such as include guards, but that's
about as far as it should go. Alright, sometimes, *sometimes*, a macro can
be both elegant and readable, but those cases are exceptions and do not
warrant an expansion of the preprocessor, IMO. Or, summarizing: macros are
evil, and should be avoided whenever possible, not encouraged.
X.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Steve Clamage <stephen.clamage@sun.com>
Date: 2000/07/21 Raw View
Thierry Grellier wrote:
>
> I don't know to which extent the C++ preprocessor is part of the
> language. I know that its usage isn't that much recommanded, but with
> some frameworks it is helpful having macros avoiding replication of a
> lot of code. This also preserves flexibility in framework evolution :
> that allows modifying the framework with minimizing changes on code
> based on it.
Macros are part of the language, but except for conditional
compilation, they are seldom needed in C++. Other applications
of macros are usually better accomplished by other constructs
in C++.
The major problem with macros is that they ignore scope. Any visible
macro definition can affect 3rd-party code brought into your translation
unit. Increasing the usefulness of macros is not usually considered
desirable for C++. If macros turn out to solve a problem for which
there is no other good solution, it might be worthwhile to propose
a language change to eliminate the need for macros in that case.
Your example of using a macro to generate boilerplate for functions
could be implemented using templates and other non-macro language
features.
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Trevor L. Jackson, III" <fullmoon@aspi.net>
Date: 2000/07/21 Raw View
A simpler solution is "#define COMMA ," -- and then use COMMA when you have to
use one in a macro argument.
Thierry Grellier wrote:
> Hello,
>
> I don't know to which extent the C++ preprocessor is part of the
> language. I know that its usage isn't that much recommanded, but with
> some frameworks it is helpful having macros avoiding replication of a
> lot of code. This also preserves flexibility in framework evolution :
> that allows modifying the framework with minimizing changes on code
> based on it.
>
> So yes I use macros, but I'm limited with the preprocessor variables
> delimitation. Here is a dummy example (I know there are some work around
> here, but it is just to illustrate). Suppose the framework needs you to
> write nearly always the same methods for each new classes :
>
> void C1::method() {
> pre();
> Body
> post();
> }
>
> void C2::method() {
> pre();
> Body
> post();
> }
>
> ...
>
> void C_n::method() {
> pre();
> Body
> post();
> }
>
> I will define the follwoing macro :
> #define METHOD(Class, Body) \
> void Class::method() {\
> pre(); \
> Body \
> post(); \
> }
>
> It works fine until a comma is used in Body argument because the
> preprocessor which has a limited tokenizer.
>
> METHOD(c1, a = b; if (c < d) f();) ok
> METHOD(c2, f(a, b, c)) ok => parenthesis are well managed
> METHOD(c2, cout << "f(a, b, c)") ok => quotes are well managed
> METHOD(c3, static t[2] = { 0, 1 };) nok => found one more parameter
> because {} are not considered as parenthesis
> METHOD(c4, T<T1, 3> v; v->method();) nok => found one more parameter
> because <> are not considered as parenthesis
>
> So here is a suggested solution :
> Instead of adding {} and <> as parenthesis, one may think of dedicating
> some tokens to help finding the boundaries of a parameter (# for example
> so far it is already a prepro reserved token). They act like
> parenthesis, but are not expanded.
> METHOD(c4, #T<T1, 3> v; v->method();#)
> METHOD(c3, #static t[2] = { 0, 1 };#)
>
> The advantage of such a solution is that this preserves the overloading
> of macro names (even though this isn't accpeted yet I think), and this
> avoid ambiguities with < > : M(a < b , c > d) one or two parameters ?.
> The modification to the preprocessor are also quite limited.
>
> Does something like this already exist ?
>
> regards,
> --
> Thierry Grellier (mailto:t.grellier@arexsys.com)
> R&D, Engineer
> http://www.arexsys.com
> tel : +33 476 18 1717 - Fax : +33 (0) 476 61 9393
>
> ---
> [ comp.std.c++ is moderated. To submit articles, try just posting with ]
> [ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
> [ --- Please see the FAQ before posting. --- ]
> [ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 2000/07/21 Raw View
In article <397582AD.8167786@arexsys.com>, Thierry Grellier
<t.grellier@arexsys.com> writes
>The advantage of such a solution is that this preserves the overloading
>of macro names (even though this isn't accpeted yet I think), and this
>avoid ambiguities with < > : M(a < b , c > d) one or two parameters ?.
>The modification to the preprocessor are also quite limited.
FWIW I think your approach leaves something to be desired. If you do
this sort of thing strictly in your own code and it never goes near
another programmer (now or in the future) then the resulting problems
are all yours. However when I want to do this sort of thing I either use
a scripting language to generate the requisite code or I simply hot key
my text editor. Both these solutions have the advantage that they are
simple and generate code that is the same that the compiler sees.
Francis Glassborow Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Thierry Grellier <t.grellier@arexsys.com>
Date: 2000/07/21 Raw View
Francis Glassborow wrote:
>
> In article <397582AD.8167786@arexsys.com>, Thierry Grellier
> <t.grellier@arexsys.com> writes
> >The advantage of such a solution is that this preserves the overloading
> >of macro names (even though this isn't accpeted yet I think), and this
> >avoid ambiguities with < > : M(a < b , c > d) one or two parameters ?.
> >The modification to the preprocessor are also quite limited.
>
> FWIW I think your approach leaves something to be desired. If you do
> this sort of thing strictly in your own code and it never goes near
> another programmer (now or in the future) then the resulting problems
> are all yours. However when I want to do this sort of thing I either use
This is precisely, because it goes to another programmer that I want to
use this : I don't him to be distracted by the internals, and I want him
to be familiar with the construct he knows in another language. I'm ok
with templates definition, and I use them as far as I can. But they can
not express combined language constructs, and we can not use template
parameters to name objects. So when I need this, I consider using
macros.
Now here something closer to illustrate when I would use macro.
template <class T> class Callback {
void (T::*m) () method;
T* object;
...
};
class C {
protected:
Callback<C> i_cb1;
void cb1();
Callback<C> i_cb2;
void cb2();
}
C::C()
{
cb1.setCb(this, C::cb1);
cb2.setCb(this, C::cb2);
}
with macros:
#define MYORG_CB_DECL(C, cb)\
Callback<C> i_cb; \
void cb()
#define MYORG_CB_INIT(C, cb) \
i_##cb.setCb(this, C::cb)
class C {
protected:
MYORG_CB_DECL(C, cb1);
MYORG_CB_DECL(C, cb2);
};
C::C()
{
MYORG_CB_INIT(C, cb1);
MYORG_CB_INIT(C, cb2);
}
MYORG_CB_IMPL(C, cb1) {
...
}
Now imagine C is a multi parameter template, you are bored.
So at the moment I can't use parameter typename within templates (the
##) and can't declare variables as templates. And I'm afraid I'll have
to wait long for this.
Now, something about the side effect of non scope macro. The solution is
quite the same as the one already used : giving naming rules for example
use prefix related to the organization. Even if this is not a language
item (like a namespace can be), this limits risks od side effect with
macros. The risks and the solutions are just the same as for every
global scope names.
> a scripting language to generate the requisite code or I simply hot key
> my text editor. Both these solutions have the advantage that they are
> simple and generate code that is the same that the compiler sees.
Yes I could imagine using scripts, or detailling the documentation on
how implementing the callback. The problem is then that my definition of
callback is doomed to be invariant, because all the written code
following the pattern rule would have to modified, because you can
hardly justify modifying it everywhere. Whereas using macro gives a bit
more flexibility : as long as the macro has the same parameters, the
user code don't need to be modified.
For example doing all these changes don't require rewritting code, but
only a recompilation:
#define MYORG_CB_DECL(C,cb) \
void cb()
#define MYORG_CB_INIT(C, cb) \
CallbackManager::register(new Callback<C>(this, C::cb, #C "::" #cb,
__FILE__, __LINE__))
Note there are also no equivalent of #par in templates.
I'm also thinking of another case. Before dynamic_cast<> was introduced
within C++ language, one used to set some macros to obtain a similar
feature. Once it has been introduced, why keeping redundancy with
the macros ? It was easy first to change the macro implementation to use
the language features : the evolution have simply required
recompilation (and sometimes it was better to keep a workaround macro
because of buggy compilers that didn't expect null as an entry of
dynamic_cast<>).
A lot of companies has done a huge usage of macros to hide framework
complexity or to limit the code to write, for example OO databases. We
are all in the mood : I dislike the macros usage, but their benefits
sometimes justify their usage. Yet I don't like the idea that the
general disapprobation of macros tend to make ignoring easy improvments
that could give the feature far before the language can give them in a
proper way.
By the way thank you for the COMMA trick. This doesn't work in depth,
but that will be ok for me !
regards,
Thierry
--
Thierry Grellier (mailto:t.grellier@arexsys.com)
R&D, Engineer
http://www.arexsys.com
tel : +33 476 18 1717 - Fax : +33 (0) 476 61 9393
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]