Topic: Small Ideas for Future C++ (void expressions, generalised type declarations, template typedef, inferred return type)


Author: Wouter Van Alboom <wouter.vanalboom@telenet.be>
Date: Thu, 27 May 2010 13:09:09 CST
Raw View
On Mar 29, 9:13 pm, Colin <goo...@icemx.net> wrote:
>   template< typename F, typename ... As >
>   typename result_of< F >::type wrap( As && ... as )
>   {
>      my_debug( std::forward< As >( as ) ... );
>      // No need to use a helper class specialised on "void" to
> supress instantiating a "void" variable.
>      auto result = F( std::forward< As >( as ) ... );
>      std::cout << result << std::endl;  // Rely on the operator
> above, even for the "void" case.
>      return result;
>   }

I also have written wrappers and function adaptors comparable to this
one. This required me than to write partial template specialisations
for functions returning void.

Recently I found out that I can handle a void returntype just like any
other type by overloading the comma-operator.
I believe this is an interesting technique, and although it's quite
obvious I did not find simular uses/hacks of the comma-operator on the
web yet.

#include <iostream>

// overloaded comma operator for non-void types
template <class _A>
struct CoutComma {
   _A operator, (_A const& arg)
   {
       std::cout << arg << std::endl;
       return arg;
   }
};

// use default comma operator for void types
template <>
struct CoutComma<void> {};


// voidable comma-argument
template <class _R>
_R Call( _R(*fun)(void) )
{
   // doesn't matter if fun returns void or non-void
   return CoutComma<_R>() , fun();
}

// some functions
int f1() { return 1; }
void f() { return; }

int main()
{
   Call(f1);
   Call(f);
}


Instead of printing like this example does you could do about anything
(buffering,marshalling,...) with the 'voidable comma-argument'.
I don't know exactly how this affects my code in terms of efficiency
and portability. It looks to me like the code became actually simpler:
* now using a total template specialization instead of partial
specializations
* I suppose the compiler is allowed to and can easily optimize away
the instance of the class CoutComma<void>


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Thu, 27 May 2010 16:09:14 CST
Raw View
Wouter Van Alboom wrote:

> On Mar 29, 9:13 pm, Colin <goo...@icemx.net> wrote:
>>   template< typename F, typename ... As >
>>   typename result_of< F >::type wrap( As && ... as )
>>   {
>>      my_debug( std::forward< As >( as ) ... );
>>      // No need to use a helper class specialised on "void" to
>> supress instantiating a "void" variable.
>>      auto result = F( std::forward< As >( as ) ... );
>>      std::cout << result << std::endl;  // Rely on the operator
>> above, even for the "void" case.
>>      return result;
>>   }
>
> I also have written wrappers and function adaptors comparable to this
> one. This required me than to write partial template specialisations
> for functions returning void.
>
> Recently I found out that I can handle a void returntype just like any
> other type by overloading the comma-operator.
> I believe this is an interesting technique, and although it's quite
> obvious I did not find simular uses/hacks of the comma-operator on the
> web yet.
>

I've first seen that hack used here:
http://groups.google.com/group/comp.lang.c++.moderated/msg/e5fbc9305539f699
and have since used this technique in various occasions, including putting
"void()" explicitly for C++0x' decltype as in
http://stackoverflow.com/questions/75538/hidden-features-of-
c/2176258#2176258 .

The article at http://stackoverflow.com/questions/1386183/how-to-call-a-
templated-function-if-it-exists-and-something-else-otherwise/1386390#1386390<http://stackoverflow.com/questions/1386183/how-to-call-a-
templated-function-if-it-exists-and-something-else-otherwise/1386390#1386390>
uses the hack too.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =?ISO-8859-1?Q?Pedro_Lamar=E3o?= <pedro.lamarao@ccppbrasil.org>
Date: Sat, 29 May 2010 15:26:26 CST
Raw View
Potatoswatter wrote:

> concurrently( task_a(), task_b() ); // compiler decides whether to
> spawn a thread

Is the function call expression really necessary?
Isn't the following well formed?

auto x = ( task_a(), task_b() );
// x has the value of the last sub-expression

This seems an interesting idea.
Makes me think of OpenMP.

--
 P.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Mon, 29 Mar 2010 14:09:22 CST
Raw View
On 29 Mrz., 21:13, Colin <goo...@icemx.net> wrote:
> Template Typedef
>
> Given a definition or declaration of a class template, e.g.
>
>   template< typename T, typename U > struct foo { /*...*/ };
>
> enable the following
>
>   template< typename T > typedef foo< T, int > bar;
>
> as shortcut for writing
>
>   template< typename T > struct bar { typedef foo< T, int > type; }
>
> and then needing
>       [typename] bar::type
>
> instead of
>
>   bar
>
> everywhere. This is an old and well-known issue, was it not addressed
> in C++0x, or did I miss something?

You did miss something:

template< typename T >
using bar = foo< T, int >;

is part of C++0x, it's called template alias.

Greetings from Bremen,

Daniel Kr   gler


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Miles Bader <miles@gnu.org>
Date: Tue, 30 Mar 2010 10:52:15 CST
Raw View
Daniel Kr   gler <daniel.kruegler@googlemail.com> writes:
> template< typename T >
> using bar = foo< T, int >;
>
> is part of C++0x, it's called template alias.

Incidentally, how come they needed the wacky new syntax, rather than
"template<typename T> typedef foo<T> bar;" or something?

Thanks,

-Miles

--
Quotation, n. The act of repeating erroneously the words of another. The words
erroneously repeated.

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =3D?ISO-8859-1?Q?Daniel_Kr=3DFCgler?=3D <daniel.kruegler@googlemail.c=.om>
Date: Wed, 31 Mar 2010 18:00:24 CST
Raw View
On 30 Mrz., 18:52, Miles Bader <mi...@gnu.org> wrote:
> Daniel Kr=FCgler <daniel.krueg...@googlemail.com> writes:
> > template< typename T >
> > using bar = foo< T, int >;
>
> > is part of C++0x, it's called template alias.
>
> Incidentally, how come they needed the wacky new syntax, rather than
> "template<typename T> typedef foo<T> bar;" or something?

This has been thought of, but was rejected, see e.g.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1449.pdf
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1489.pdf

Among the reasons:

1) A template alias is no type alias, it's an alias for a family of
types and bar is no "typedef" name.

2) The new syntax also points out much clearer, where the
template parameter(s) belong to.

The win of (2) becomes more clear by an example: Consider
this typical typedef:

typedef double (*analysis_fp)(const vector<Student_info>&);

It's much harder to parse (and I mean for the human here) than

using analysis_fp = double (*)(const vector<Student_info>&);

This has lead to the decision to allow the alias declaration via
using also in non-template context as above (where it has the
name /alias-declaration/).

HTH & Greetings from Bremen,

Daniel Kr=FCgler




--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Colin <google@icemx.net>
Date: Wed, 31 Mar 2010 18:17:41 CST
Raw View
On Mar 29, 10:09 pm, Daniel Kr=FCgler <daniel.krueg...@googlemail.com>
wrote:
> On 29 Mrz., 21:13, Colin <goo...@icemx.net> wrote:
>
> > Template Typedef
>
> > Given a definition or declaration of a class template, e.g.
>
> >   template< typename T, typename U > struct foo { /*...*/ };
>
> > enable the following
>
> >   template< typename T > typedef foo< T, int > bar;
>
> > as shortcut for writing
>
> >   template< typename T > struct bar { typedef foo< T, int > type; }
>
> > and then needing
> >       [typename] bar::type
>
> > instead of
>
> >   bar
>
> > everywhere. This is an old and well-known issue, was it not addressed
> > in C++0x, or did I miss something?
>
> You did miss something:
>
> template< typename T >
> using bar = foo< T, int >;
>
> is part of C++0x, it's called template alias.

Thanks =97 so a template typedef is called a template alias and uses (no
pun intended) the keyword using, perhaps that's why I didn't find it
earlier.

(Presumably this will also work in the non-templated case, giving a
uniform replacement for typedef that works in either case.)

Now I just have to wait for my compiler to support it...

One question/suggestion down, three more to go ;-)

Regards, Colin


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Potatoswatter <potswa@gmail.com>
Date: Wed, 31 Mar 2010 22:51:51 CST
Raw View
On Mar 29, 2:13 pm, Colin <goo...@icemx.net> wrote:

> Void Expressions and Variables
>
> Let the compiler handle void like a normal type, i.e. "as if" it were
> declared "struct void {};", with the following exceptions:

I was thinking about a restricted version of this the other day.
Namely, allowing allowing void function arguments which are ignored.

The order of evaluation of function arguments is unspecified
(5.2.2/8). If this were liberally interpreted to mean they may be
evaluated simultaneously, it would enable concurrency. Example:

inline void concurrently() { }
void task_a();
void task_b();

concurrently( task_a(), task_b() ); // compiler decides whether to
spawn a thread

It would be a pretty high-impact change, since this would also be
affected:

int task_a();
int task_b();

pair<int,int> integrated( task_a(), task_b() ); // generate halves of
the pair concurrently

But only wacky or buggy code relies on potentially-interfering side
effects    right?


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Colin <google@icemx.net>
Date: Mon, 29 Mar 2010 13:13:42 CST
Raw View
Hello Everybody,

in this post I want to collect some small ideas for extending the C++
language ... at least they sound much smaller than for example "full
compile-time introspection" or "template over identifiers".

All of these ideas were born from recurrently stumbling over some
limitations in the current language. I'm putting them up for
discussion to see whether other people have similar problems, would
propose similar solutions, or have alternative ideas for existing or
future solutions.

I have never implemented a C++ compiler, so although I believe that
these extensions should be easy to implement, this might of course not
be the case. But first things first, probably not all ideas will
survive the discussion ;-)

Regards, Colin




Generalised Type Declarations

Allow the use of

  typedef foo;

to [forward-]declare any type "foo" that is typedef'd later on, or,
even better, allow the use of

  typename bar;

to [forward-]declare any type "bar" that is defined [as class, struct,
enum, union, or typedef (!)] later on.




Inferred Function Return-Types

In the new function declarator syntax, allow the omission of the
trailing type specification in a function definition, i.e.

  auto foo( ... ) { /* ... */ }

with the following behaviour:

- The omission of the trailing type specification implicitly declares
the function as "inline",
- such a function MUST NOT be forward-declared, and
- the type of a function without return-statement is inferred as
"void",
- for one return statement "return expr;", the type is inferred as for
"auto expr;",
- for two return statements "return e1;" and "return e2;", the type is
inferred as for "auto bool() ? e1 : e2;",
- which scales up to arbitrary many return statements by chaining,
- the return type can be modified by writing e.g. "auto & foo() { /
* ... */ }" with obvious semantics.




Void Expressions and Variables

Let the compiler handle void like a normal type, i.e. "as if" it were
declared "struct void {};", with the following exceptions:

- Allow "sizeof( void )", but the value is 0.
- References decay, i.e. "void &" and "void &&" are the same type as
"void".
- Pointers to "void" do not change their behaviour.
- But, should taking the address of an object of type "void" be
allowed???
- Throwing and catching "void" is probably not necessary.

Effectively, "void" is handled like a normal type by the compiler
front-end, but no code that actually operates on a void (constructs
one, allocates memory for one, returns one, copies one) is ever
generated by the back-end.

In particular variables of type void, and overloading on type void
would be allowed; writing void() constructs an object of type void,
i.e. it does nothing at run-time, only the compiler tracks the
imaginary object of type "void".

This proposal is a straightforward extension of what is currently
already possible:

  void foo() {}
  void bar() { return foo(); }

However it has the potential to greatly simplify generic code, for
example:

  // Overload stream operator...

  inline ostream & operator<<( ostream & o, void ) { return o; }

  // ...no need to suppress dumping "void" to a stream in generic
code.

  template< typename T > struct result_of;

  template< typename R, typename ... Ts >
  struct result_of< R( Ts ... ) >
  {
     typedef R type;
  };

  template< typename F, typename ... As >
  typename result_of< F >::type wrap( As && ... as )
  {
     my_debug( std::forward< As >( as ) ... );
     // No need to use a helper class specialised on "void" to
supress instantiating a "void" variable.
     auto result = F( std::forward< As >( as ) ... );
     std::cout << result << std::endl;  // Rely on the operator
above, even for the "void" case.
     return result;
  }

  void baz();

  auto i = std::make_pair( 42, wrap< baz >() );  // Ok, infers
std::pair< int, void >.
  std::cout << i.first << " " << i.second;  // Ok...




Template Typedef

Given a definition or declaration of a class template, e.g.

  template< typename T, typename U > struct foo { /*...*/ };

enable the following

  template< typename T > typedef foo< T, int > bar;

as shortcut for writing

  template< typename T > struct bar { typedef foo< T, int > type; }

and then needing
      [typename] bar::type

instead of

  bar

everywhere. This is an old and well-known issue, was it not addressed
in C++0x, or did I miss something?

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]