[dune-functions] Fwd: Paper: The interface for functions in the dune-functions module

Carsten Gräser graeser at mi.fu-berlin.de
Tue Mar 1 00:30:28 CET 2016


Hi,

Am 29.02.2016 um 21:03 schrieb Oliver Sander:
> Hi guys,
> 
> today I received this email below from a colleague who happened to find our
> paper on dune-functions (he's in cc).  His comments are insightful, and you
> may find them interesting.
nice to see that someone is interested in this.
I'll give some comments to this below:

> -------- Forwarded Message --------
> Subject: Paper: The interface for functions in the dune-functions module
> Date: Mon, 29 Feb 2016 14:17:15 +0000
> From: Simon Praetorius <Simon.Praetorius at tu-dresden.de>
> To: oliver.sander at tu-dresden.de
[...]
> Ein paar kleine Hinweise/Anmerkungen/Fragen hätte ich allerdings noch:
> - Der Ansatz die Konzepte eines Templates mittels static_assert zu
> überprüfen sind recht angenehm. Man kann explizit eine Fehlermeldung
> formulieren. Allerdings ändert dies quasi nichts an der Signatur der
> Funktion, sondern erzeugt eine Fehlermeldung erst bei Instantiierung
> des Funktionsrumpfes. Das führt dazu, dass man in der Regel noch viele
> Weitere Fehlermeldungen bekommt, die auf dem nicht erfüllten Konzept
> des Funktionsarguments folgen. Z.B.
> 
> 1: template <class F, class T>
> 2: double call(F&& f, T&& x)
> 3: {
> 4:   static_assert( concept::Function<F, double(double)>::value, "Fehler" );
> 5:   return f(std::forward<T>(x));
> 6: }
> 
> erzeugt zuerst die gewollte Fehlermeldung "Fehler" und danach einen
> weitere Fehler, dass in Zeile 5 das Objekt f nicht als Funktion
> verwendet werden kann. Das ist in diesem Fall sogar die richtige
> Fehlermeldung, nur wollte man sie eigentlich durch das static_assert
> vorher abfangen. Das bedeutet: Bei komplizierten Funktionen kommen
> möglicherweise sehr viele Fehlermeldungen und irgendwo dazwischen ist
> dann das static_assert und man muss suchen was eigentlich der Auslöser
> für den Fehler war.
> 
> Ich persönlich finde es schicker wenn die Konzept-Überprüfung bereits
> bei der Instantiierung der Templates geschieht (und damit
> gewissermaßen in die Signatur der Funktion mit eingeht). D.h. man
> würde etwas früher abbrechen und der komplette Inhalt der Funtion wäre
> noch gar nicht relevant und würde keine weiteren Fehler provozieren:
> 
> 1: template <class F, class T, class =
> 2:   requires<concept::Function<F, double(double)>> >
> 3: double call(F&& f, T&& x)
> 4: {
> 5:   return f(std::forward<T>(x));
> 6: }
> 
> Wobei 'requires' hier ein einfaches Alias für enable_if ist:
> 
> 1: template <class C, class T = void>
> 2: using requires = typename std::enable_if< C::value, T>::type;
> 
> Dies produziert leider nicht immer so aussagekräftige Fehlermeldungen
> wie ein static_assert. Mit ein paar "Tricks" kann man das aber
> trotzdem produzieren mit einer kleinen Abwandlung und einem Macro als
> Unterstützung:
> 
> 0: #define ERROR(...) bool
> 1: template <class C, class T = bool>
> 2: using requires = typename std::enable_if< C::value, T>::type;
> 3: template <class F, class T,
> 4:   requires< concept::Function<F, double(double)> > = ERROR( Fehler ) >
> 5: double call(F&& f, T&& x) { ... }
> 
> Zumindest im gcc Wird dann der Fehlertext mit ausgegeben in der Fehlermeldung.
This approach has its own drawbacks: If you have several overloads
the compiler errors can get really long because you get spammed
with all the information on why substitution failed for any of
your overloads.

It seems that a little trick combining both ideas leads to the
nicest error messages:

You constrain your overload by a concept check and add an additional
overload that is constrained to not matching the concept. The latter
is empty up to a static assert with concept check. Then you don't get
any overload errors because the dummy matches. This however produces
only the desired error, because it does not use the type in bogus
ways. We recently used this trick in dune-typetree:

  https://gitlab.dune-project.org/pdelab/dune-typetree/commit/1230fc4084eb425137c772498bb67d8e6301f033


> - Bei der Implementierung von dune_function (als Erweiterung von
> std::function) nutzt ihr einen Konstruktor mit universal-referenz als
> Argument:
> 
> 1: template < class Range , class Domain >
> 2: struct dune_function < Range ( Domain ) >
> 3: {
> 4:   template < class F >
> 5:   dune_function ( F && f ) :
> 6:     f_ ( new FunctionWrapper < Range < Domain > , F >( f ) )
> 7:   {}
> 8: // ...
> 9: }
> 
> Möglicherweise sind nicht alle Details im Paper erwähnt und
> ausgeführt. Wenn ihr in FunctionWrapper sowieso nur Funktionen als
> const& akzeptiert, macht es eventuell keinen Sinn eine
> universal-reference im dune_function Konstruktor zu akzeptieren. Dies
> führt nur zu weiteren Komplikationen: Damit wird der klassische
> Copy-Konstruktor und Move-Konstruktor verdeckt. Man müsste (wieder
Here the example in the paper was really only a prototype.
In dune-functions itself we exclude copy and move from
the gready constructor using a simple helper:

  https://gitlab.dune-project.org/staging/dune-functions/blob/master/dune/functions/common/differentiablefunction.hh#L98

The helper itself has meanwhile arrived in dune-common:

  https://gitlab.dune-project.org/core/dune-common/blob/master/dune/common/typeutilities.hh#L30

Best regards and thanks for your comments and suggestions!

Carsten

> mittels einer Art Konzepte) zusätzlich noch ausschließen dass 'F' vom
> Typ 'dune_function' ist, z.B.
> 
> 4:   template < class F, class =
> 5:     requires<!is_same< std::decay_t<F>, dune_function >> >
> 6:   dune_function ( F && f )
> 
> Außerdem würde ich dann auch entsprechend 'FunctionWrapper < Range <
> Domain > , F >( f )' ersetzen durch
> 
> 1: FunctionWrapper < Range < Domain > , std::decay_t<F> >(
> std::forward<F>(f) )
> 
> um mögliche Komplikationen bei der automatische Type-Ableitung zu vermeiden.
> 
> 
> Viele Grüße,
> Simon

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: OpenPGP digital signature
URL: <https://lists.dune-project.org/pipermail/dune-functions/attachments/20160301/266670bc/attachment.sig>


More information about the dune-functions mailing list