Topic: notion: __args__


Author: Matthew Woehlke <mw_triad@users.sourceforge.net>
Date: Mon, 02 Feb 2015 17:10:34 -0500
Raw View
Here's an offhand thought... define __args__, which expands to a
(potentially empty) parameter pack of all arguments passed to the
current function, *including unnamed arguments*.

Why?

  template <typename... Args>
  trampoline(char const* method, Args... args);

  #define TRAMPOLINE() trampoline(__func__, __args__)

I've written this mess out longhand many times in Qt code, substituting
'trampoline' with 'QMetaObject::invokeMethod' in order to implement
thread safe methods. (If called from a thread other than the one that
owns the object, an event is created on the owning thread's queue to
invoke the slot on the owning thread. This check, and the immediate
return, are elided; hopefully you get the idea.) I recently wrote a new
version of this using C++11 variadic templates so that I don't have to
write out the parameter types longhand (sweet!), but I still have to
repeat the list of arguments to the method. It would be really, really
cool if there was a way to omit even this and just stick something like
a 'MAKE_ME_THREAD_SAFE()' at the top of methods where I want that
functionality.

Sound interesting? Has anyone else wanted something like this? (Is there
a way to do it already that I don't know?)

Note that this exact case also relies on the assumption that __func__ is
the undecorated, unqualified (including the owning class) name of the
current function, which (AFAIK) is not guaranteed by the standard.
Considering that there exist use cases like this, would it be
interesting to have a standard identifier by which such name is
guaranteed obtainable?

--
Matthew

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

.


Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Mon, 02 Feb 2015 23:42:06 +0100
Raw View
On 02/02/2015 11:10 PM, Matthew Woehlke wrote:
> Here's an offhand thought... define __args__, which expands to a
> (potentially empty) parameter pack of all arguments passed to the
> current function, *including unnamed arguments*.
>
> Why?
>
>   template <typename... Args>
>   trampoline(char const* method, Args... args);
>
>   #define TRAMPOLINE() trampoline(__func__, __args__)

I'm sorry, I don't know what exactly you're talking about.
Could you please show a full example (including the call)
with C++14 and the same example with your proposed extension?

Thanks,
Jens

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

.


Author: Matthew Woehlke <mw_triad@users.sourceforge.net>
Date: Tue, 03 Feb 2015 12:23:17 -0500
Raw View
On 2015-02-02 17:42, Jens Maurer wrote:
> On 02/02/2015 11:10 PM, Matthew Woehlke wrote:
>> Here's an offhand thought... define __args__, which expands to a
>> (potentially empty) parameter pack of all arguments passed to the
>> current function, *including unnamed arguments*.
>>
>> Why?
>>
>>   template <typename... Args>
>>   trampoline(char const* method, Args... args);
>>
>>   #define TRAMPOLINE() trampoline(__func__, __args__)
>
> I'm sorry, I don't know what exactly you're talking about.
> Could you please show a full example (including the call)
> with C++14 and the same example with your proposed extension?

Current (C++11):

  #define THREAD_SAFE(...) \
    if (QThread::currentThread() != this->thread()) \
    { reinvoke(this, __func__, __VA_ARGS__); return; }

  template <typename... Args>
  void reinvoke(QObject* object, char const* method, Args... args)
  {
    ...
  }

  void Foo::ThreadSafe(int a, double b, double c_unused)
  {
    THREAD_SAFE(a, b, c_unused)

    ...
  }

The details of how to implement reinvoke() aren't important; that helper
is the same in either case.

Now, here's the cool part (proposal):

  #define THREAD_SAFE() \
    if (QThread::currentThread() != this->thread()) \
    { reinvoke(this, __func__, __args__); return; }

  void Foo::ThreadSafe(int a, double b, double /*c*/)
  {
    THREAD_SAFE() // Note lack of arguments!

    ...
  }

The proposed __args__ expands to the arguments passed to context
function, i.e. 'a', 'b', *and the unnamed parameter*. So the 'reinvoke'
helper function is called with the exact same arguments (int, double,
double) in both cases. Now, however, I can write a magic macro that
*doesn't require repeating the arguments* to invoke the trampoline.

The implementation is really quite simple; whenever the compiler sees
__args__, it substitutes the list of arguments passed to the function
wherein __args__ appears. (Obviously it is an error to use __args__
outside of a function.)

As another example, the following would be equivalent:

  template <typename... Args> foo1(Args... args) { bar(0, args...); }
  template <typename... Args> foo2(Args... /**/) { bar(0, __args__); }

--
Matthew

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

.


Author: Sean Middleditch <sean.middleditch@gmail.com>
Date: Tue, 3 Feb 2015 11:30:45 -0800 (PST)
Raw View
------=_Part_3859_1285150667.1422991845918
Content-Type: multipart/alternative;
 boundary="----=_Part_3860_136738743.1422991845918"

------=_Part_3860_136738743.1422991845918
Content-Type: text/plain; charset=UTF-8

On Tuesday, February 3, 2015 at 9:23:32 AM UTC-8, Matthew Woehlke wrote:
>
> Now, here's the cool part (proposal):
>
>   #define THREAD_SAFE() \
>     if (QThread::currentThread() != this->thread()) \
>     { reinvoke(this, __func__, __args__); return; }
>
>   void Foo::ThreadSafe(int a, double b, double /*c*/)
>   {
>     THREAD_SAFE() // Note lack of arguments!
>
>     ...
>   }
>

Do you have any other use cases? That approach to thread safety is severely
broken.

With the proposal, is __args__ treated like a parameter pack or just a
magic macro-like thing? e.g. could I write something like:

   foo(std::forward<decltype(__args__)>(__args__)...);

Without such support, you couldn't use __args__ to forward
rvalue-references.

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

------=_Part_3860_136738743.1422991845918
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Tuesday, February 3, 2015 at 9:23:32 AM UTC-8, Matthew =
Woehlke wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-l=
eft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">Now, here's the =
cool part (proposal):
<br>
<br>&nbsp; #define THREAD_SAFE() \
<br>&nbsp; &nbsp; if (QThread::currentThread() !=3D this-&gt;thread()) \
<br>&nbsp; &nbsp; { reinvoke(this, __func__, __args__); return; }
<br>
<br>&nbsp; void Foo::ThreadSafe(int a, double b, double /*c*/)
<br>&nbsp; {
<br>&nbsp; &nbsp; THREAD_SAFE() // Note lack of arguments!
<br>
<br>&nbsp; &nbsp; ...
<br>&nbsp; }
<br></blockquote><div><br></div><div>Do you have any other use cases? That =
approach to thread safety is severely broken.</div><div><br></div><div>With=
 the proposal, is __args__ treated like a parameter pack or just a magic ma=
cro-like thing? e.g. could I write something like:</div><div><br></div><div=
>&nbsp; &nbsp;foo(std::forward&lt;decltype(__args__)&gt;(__args__)...);</di=
v><div><br></div><div>Without such support, you couldn't use __args__ to fo=
rward rvalue-references.</div><div><br></div></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_3860_136738743.1422991845918--
------=_Part_3859_1285150667.1422991845918--

.


Author: Matthew Woehlke <mw_triad@users.sourceforge.net>
Date: Tue, 03 Feb 2015 15:41:49 -0500
Raw View
On 2015-02-03 14:30, Sean Middleditch wrote:
> On Tuesday, February 3, 2015 at 9:23:32 AM UTC-8, Matthew Woehlke wrote:
>> Now, here's the cool part (proposal):
>>
>>   #define THREAD_SAFE() \
>>     if (QThread::currentThread() != this->thread()) \
>>     { reinvoke(this, __func__, __args__); return; }
>>
>>   void Foo::ThreadSafe(int a, double b, double /*c*/)
>>   {
>>     THREAD_SAFE() // Note lack of arguments!
>>
>>     ...
>>   }
>
> Do you have any other use cases? That approach to thread safety is severely
> broken.

I am surprised to hear that you think the Qt::AutoConnection method of
calling slots on signal emission is "severely broken". I am sure this
comes as a great surprise to just about every Qt developer.

The idea is quite simple: when a signal is emitted, iterate over all
connected slots. If the receiver object lives in the current thread,
just call the slot (direct connection). Otherwise, make a copy of the
arguments and insert them into an event which is tossed onto the queue
of the receiving thread (queued connection). This event will
subsequently execute the slot with the copied arguments when the
receiving thread's event loop gets around to processing it. (To be
clear, the method *does* execute asynchronously from the caller's
perspective. That's as expected.)

That's what Qt::AutoConnection does, and I'd be really, *really*
surprised if it is "severely broken" given how widely Qt is used. It's
also exactly the same as what *I* am doing, just at a slightly different
point/level, with 'signal emission' replaced by the slot being called,
and thus my dispatch logic living in the slot itself rather than the
bowels of QObject internals.

I've used this *specific* technique (sans the new simplifications made
possible by C++11) before on multiple occasions, and in multiple
projects even. Indirectly (via signals/slots) I use it *all the time*.
I'm quite confident that it is not broken. Personally, some adjectives I
find applicable are "simple" and "elegant".

If you really think this is "broken", I (and a lot of other Qt
developers) would really like to know how...

> With the proposal, is __args__ treated like a parameter pack or just a
> magic macro-like thing? e.g. could I write something like:
>
>    foo(std::forward<decltype(__args__)>(__args__)...);

Either one would work for my use case, although I would consider it
better if your example was also supported. (It's no problem if I have to
write 'foo(__args__...)' rather than 'foo(__args__)'; that might even be
a *good* thing.)

--
Matthew

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

.


Author: Sean Middleditch <sean@middleditch.us>
Date: Tue, 3 Feb 2015 17:32:11 -0800
Raw View
On Tue, Feb 3, 2015 at 12:41 PM, Matthew Woehlke
<mw_triad@users.sourceforge.net> wrote:
> The idea is quite simple: when a signal is emitted, iterate over all
> connected slots. If the receiver object lives in the current thread,
> just call the slot (direct connection). Otherwise, make a copy of the
> arguments and insert them into an event which is tossed onto the queue
> of the receiving thread (queued connection). This event will

Well that bit of key context was left out entirely, now, wasn't it? :p

You might still want some more use cases. There are definitely other
ways of achieving the same thread-aware callback than what Qt
apparently does, so by itself that's not the strongest motivation for
a language feature. I'm trying to think of a good one to suggest (I
like the idea on the surface) but everything I can come up with is
already solved by variadic function templates or would additionally
need lazy evaluation (which macros provide). I think the idea is a
good one, but it needs some solid proof.

Claiming that it's simple to implement isn't good enough unless you
have a patch to GCC or Clang that implements it. :)

>> With the proposal, is __args__ treated like a parameter pack or just a
>> magic macro-like thing? e.g. could I write something like:
>>
>>    foo(std::forward<decltype(__args__)>(__args__)...);
>
> Either one would work for my use case, although I would consider it
> better if your example was also supported. (It's no problem if I have to
> write 'foo(__args__...)' rather than 'foo(__args__)'; that might even be
> a *good* thing.)

I think the big problem is forwarding, even in your use case. Without
acting like a parameter pack, __args__ wouldn't work for move-only
types like unique_ptr. If you're going to write a paper on this, you
might want to strongly consider going the parameter pack route.

--
Sean Middleditch
http://seanmiddleditch.com

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

.


Author: Thiago Macieira <thiago@macieira.org>
Date: Tue, 03 Feb 2015 23:30:21 -0800
Raw View
On Tuesday 03 February 2015 17:32:11 Sean Middleditch wrote:
> You might still want some more use cases. There are definitely other
> ways of achieving the same thread-aware callback than what Qt
> apparently does, so by itself that's not the strongest motivation for
> a language feature. I'm trying to think of a good one to suggest (I
> like the idea on the surface) but everything I can come up with is
> already solved by variadic function templates or would additionally
> need lazy evaluation (which macros provide). I think the idea is a
> good one, but it needs some solid proof.

Here's an idea: a dispatcher to more optimised versions:

void function(int a, double b, double c_unused)
{
 if (cpuSupports(SSE2))
  function_sse2(__args__);
 else
  function_generic(__args__);
}

Another one is dispatching to a library you've dynamically loaded manually.
Right now, I have this for libdbus-1:

# define DEFINEFUNC(ret, func, args, argcall, funcret)          \
    typedef ret (* _q_PTR_##func) args;                         \
    static inline ret q_##func args                             \
    {                                                           \
        static _q_PTR_##func ptr;                               \
        if (!ptr)                                               \
            ptr = (_q_PTR_##func) qdbus_resolve_me(#func);      \
        funcret ptr argcall;                                    \
    }

used like:
DEFINEFUNC(DBusConnection *, dbus_bus_get_private, (DBusBusType     type,
                                                    DBusError      *error),
           (type, error), return)

Which is an improvement over prior OpenSSL dispatcher (see
http://code.woboq.org/qt5/qtbase/src/network/ssl/qsslsocket_openssl_symbols_p.h.html#75)

Now, __args__ would not get rid of the macro, but it might result in a simpler
function body.

I've also looked into GCC's __builtin_apply_args() but I've never figured out
how it's supposed to work.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center
      PGP/GPG: 0x6EF45358; fingerprint:
      E067 918B B660 DBD1 105C  966C 33F5 F005 6EF4 5358

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

.


Author: Matthew Woehlke <mw_triad@users.sourceforge.net>
Date: Wed, 04 Feb 2015 12:16:13 -0500
Raw View
On 2015-02-03 20:32, Sean Middleditch wrote:
> On Tue, Feb 3, 2015 at 12:41 PM, Matthew Woehlke wrote:
>> The idea is quite simple: when a signal is emitted, iterate over all
>> connected slots. If the receiver object lives in the current thread,
>> just call the slot (direct connection). Otherwise, make a copy of the
>> arguments and insert them into an event which is tossed onto the queue
>> of the receiving thread (queued connection). This event will
>
> Well that bit of key context was left out entirely, now, wasn't it? :p

Hey, you're the one that called it "severely broken" with apparently no
idea at all what reinvoke() actually does :-).

(I did actually mention QMetaObject::invokeMethod in the original post,
though I'm not surprised you didn't go out of your way to look it up;
that would have been something of an unfair expectation.)

> You might still want some more use cases. There are definitely other
> ways of achieving the same thread-aware callback than what Qt
> apparently does, so by itself that's not the strongest motivation for
> a language feature. I'm trying to think of a good one to suggest (I
> like the idea on the surface) but everything I can come up with is
> already solved by variadic function templates or would additionally
> need lazy evaluation (which macros provide). I think the idea is a
> good one, but it needs some solid proof.

Sure. I agree by itself it isn't a very strong motivation. Part of
posting was to see what other people thought and potentially collect
other use cases.

> I think the big problem is forwarding, even in your use case. Without
> acting like a parameter pack, __args__ wouldn't work for move-only
> types like unique_ptr. If you're going to write a paper on this, you
> might want to strongly consider going the parameter pack route.

Agreed in general. For my *specific* use case, however, it doesn't
matter, because Qt can't pass non-copyable parameters across threads.
(More to the point, it can't pass non-copyable parameters *from
signals*, for a very good reason; the number of receivers is zero to many.)

--
Matthew

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

.


Author: Matthew Woehlke <mw_triad@users.sourceforge.net>
Date: Wed, 04 Feb 2015 12:31:20 -0500
Raw View
On 2015-02-04 02:30, Thiago Macieira wrote:
> Here's an idea: a dispatcher to more optimised versions:
>
> void function(int a, double b, double c_unused)
> {
>  if (cpuSupports(SSE2))
>   function_sse2(__args__);
>  else
>   function_generic(__args__);
> }

I would guess most real-world instances of this might use macros to help
out... but they'd still have the issue like your next example:

> # define DEFINEFUNC(ret, func, args, argcall, funcret)          \
>     typedef ret (* _q_PTR_##func) args;                         \
>     static inline ret q_##func args                             \
>     {                                                           \
>         static _q_PTR_##func ptr;                               \
>         if (!ptr)                                               \
>             ptr = (_q_PTR_##func) qdbus_resolve_me(#func);      \
>         funcret ptr argcall;                                    \
>     }
>
> used like:
> DEFINEFUNC(DBusConnection *, dbus_bus_get_private, (DBusBusType     type,
>                                                     DBusError      *error),
>            (type, error), return)

  # define DEFINEFUNC(ret, func, args, funcret)                   \
      typedef ret (* _q_PTR_##func) args;                         \
      static inline ret q_##func args                             \
      {                                                           \
          static _q_PTR_##func ptr;                               \
          if (!ptr)                                               \
              ptr = (_q_PTR_##func) qdbus_resolve_me(#func);      \
          funcret ptr(__args__)                                   \
      }

  DEFINEFUNC(DBusConnection *, dbus_bus_get_private,
             (DBusBusType type, DBusError *error), return)

Not a *huge* improvement, but a little better... and as a "bonus", the
parameter names become optional. (I would probably have two helper
macros to invoke that one - one for void functions, and one for
non-void, to avoid the 'return' in actual invocations - but that's
beside the point.)

If there was a way to access the enclosing function *as a type object*,
you could greatly simplify the above to:

  #define DBUS_WRAP_WITH_RESULT() \
    using FuncPtr = /* new magic */; \
    static FuncPtr ptr = (FuncPtr)qdbus_resolve_me(__func__); \
    return (*ptr)(__args__);

  static inline dbus_bus_get_private(DBusBusType type, DBusError *error)
  {
    DBUS_WRAP_WITH_RESULT();
  }

....which has the nice benefit of not hiding the declaration in a macro,
while being similar amount of typing.

--
Matthew

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

.