Topic: identifiers as template arguments and compile-time regexps for
Author: diener896092_no_spam_here@bellsouth.net (Edward Diener)
Date: Sat, 29 Dec 2007 00:54:01 GMT Raw View
Colin wrote:
> Hallo,
>
> in the last couple of months I have repeatedly stumbled over
> limitations in the C++ language, some of which I will try to isolate,
> write about, and share for discussion...
>
> (These issues all arose while working on real-life code; the code
> snippets below are however mostly not complete, and not real C++
> (because they show what I would like to be able to write, i.e. things
> that are not currently possible)).
>
> (1) Apart from all the many-discussed shortcomings of enums ... here's
> something that I would have liked to be able to write on several
> occasions:
>
> enum foo {
> FOBBLE_FROBNICATE,
> FIZZLE_FROBNICATE,
> FOBBLE_GUNKL,
> ...
> };
>
> int bar( const foo f ) {
> switch ( f ) {
> case "FOBBLE_.*":
> return 1;
> case "FIZZLE_.*":
> return 42:
> default:
> throw "argh";
> }
> }
>
> I.e., I want the compiler to look at the definition of foo and expand
> the regular expression in the given case labels to all enum constants
> whose names match that regular expression.
You want this just to save you from having to write:
case FOBBLE_FROBNICATE:
case FOBBLE_GUNKL:
return 1;
? I think this is a very minor use case for what you desire out from the
C++ language.
>
> (2) Suppose that we allow access to matched sub-expressions; that way
> we could finally write ONE simple function that converts ANY enum
> value to its name:
>
> template< typename Enum >
> std::string to_string( const Enum e ) {
> switch ( e ) {
> case "(.*)":
> return # \\1; // some syntax to allow access to the bracketed
> sub-expressions of the supplied regular expression and convert it to a
> string
> default:
> return boost::lexical_cast< std::string >( int( e ) );
> }
> }
Run-time reflection in C++ would be a better general solution to your
problem. Unfortunately it does not seem to be much of a priority with
the standard C++ committee.
>
> (3) Now if only we could add identifiers as template parameters we
> could do e.g. some more generic forwarding:
>
> template< typename T >
> struct foo {
> // structors etc.
>
> template< identifier I >
> typeof( T::I ) get_ ## I() {
> return t_.I;
> }
>
> T t_;
> };
Sorry, I can not follow what you want here.
---
[ 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://www.comeaucomputing.com/csc/faq.html ]
Author: Colin <google@icemx.net>
Date: Sat, 29 Dec 2007 11:48:05 CST Raw View
On Dec 29, 1:54 am, diener896092_no_spam_h...@bellsouth.net (Edward
Diener) wrote:
> Colin wrote:
> > Hallo,
>
> > in the last couple of months I have repeatedly stumbled over
> > limitations in the C++ language, some of which I will try to isolate,
> > write about, and share for discussion...
>
> > (These issues all arose while working on real-life code; the code
> > snippets below are however mostly not complete, and not real C++
> > (because they show what I would like to be able to write, i.e. things
> > that are not currently possible)).
>
> > (1) Apart from all the many-discussed shortcomings of enums ... here's
> > something that I would have liked to be able to write on several
> > occasions:
>
> > enum foo {
> > FOBBLE_FROBNICATE,
> > FIZZLE_FROBNICATE,
> > FOBBLE_GUNKL,
> > ...
> > };
>
> > int bar( const foo f ) {
> > switch ( f ) {
> > case "FOBBLE_.*":
> > return 1;
> > case "FIZZLE_.*":
> > return 42:
> > default:
> > throw "argh";
> > }
> > }
>
> > I.e., I want the compiler to look at the definition of foo and expand
> > the regular expression in the given case labels to all enum constants
> > whose names match that regular expression.
>
> You want this just to save you from having to write:
>
> case FOBBLE_FROBNICATE:
> case FOBBLE_GUNKL:
> return 1;
>
> ? I think this is a very minor use case for what you desire out from the
> C++ language.
In this small example: yes. In my applications the enums are of course
much larger.
The more interesting question is whether the whole approach of using
regular expressions for code generation in such, or similar, ways can
be put to more general (and perhaps more useful) use...
> > (2) Suppose that we allow access to matched sub-expressions; that way
> > we could finally write ONE simple function that converts ANY enum
> > value to its name:
>
> > template< typename Enum >
> > std::string to_string( const Enum e ) {
> > switch ( e ) {
> > case "(.*)":
> > return # \\1; // some syntax to allow access to the bracketed
> > sub-expressions of the supplied regular expression and convert it to a
> > string
> > default:
> > return boost::lexical_cast< std::string >( int( e ) );
> > }
> > }
>
> Run-time reflection in C++ would be a better general solution to your
> problem. Unfortunately it does not seem to be much of a priority with
> the standard C++ committee.
Unfortunately. For me, serialisation and persistence are, well,
persistent problems that lead to repeated code, or code generation,
all the time because of missing features from the language.
> > (3) Now if only we could add identifiers as template parameters we
> > could do e.g. some more generic forwarding:
>
> > template< typename T >
> > struct foo {
> > // structors etc.
>
> > template< identifier I >
> > typeof( T::I ) get_ ## I() {
> > return t_.I;
> > }
>
> > T t_;
> > };
>
> Sorry, I can not follow what you want here.
The idea is to allow identifiers as template arguments, and use them
in strange ways; in this case, whenever I have an instance c of
template class C where C is an instantiation of class template foo,
and then write c.get_bar(), for any valid C++ identifier bar, the get_
member function template should be instantiated with bar as its
template argument, which results in a function that simply returns
t_.bar. (Here misusing the ## syntax from the preprocessor to paste
get_ and the template argument I together to form a new identifier.)
Other small example for this:
struct point {
double x;
double y;
};
template< identifier A, identifier B, typename T > void foo( const T &
t, std::ostream & o ) {
o << t.A << " " << t.B;
}
point p;
foo< x, y >( p );
foo< first, second >( std::pair< int, double >( 1, 42.0 ) );
..
(This could of course be even further generalised by allowing literal
code snippets as template arguments, but let's leave that out for the
moment.)
Regards, Colin
---
[ 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://www.comeaucomputing.com/csc/faq.html ]
Author: x@y.z (Martijn Meijering)
Date: Wed, 2 Jan 2008 00:17:41 GMT Raw View
Colin wrote:
> (3) Now if only we could add identifiers as template parameters we
> could do e.g. some more generic forwarding:
I find this a good suggestion. I sometimes bump into this limitation
when trying to refactor out some duplication. In a recent case I had two
structures with members that had the same name, but a similar but
different type (one was a vector type, the other a related matrix of
partial derivatives). In a number of places I wanted to loop over all
fields and I couldn't do that without either duplication or a lot of
extra code and use of some macro's. In the end I chose the latter option
because I could tuck away the complex code somewhere in a corner and it
made the rest of the code more readable. If I had had the option of
passing in an identifier, it could have been done a lot more elegantly.
Pointers to member only get you halfway through.
---
[ 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://www.comeaucomputing.com/csc/faq.html ]