Forum: Compiler & IDEs Diskussion um NTTP in C++20


von Wilhelm M. (wimalopaan)


Lesenswert?

Die Diskussion um NTTP (non-type template parameter) scheint nun beendet 
zu sein. Leider ist da

https://en.cppreference.com/w/cpp/language/template_parameters

nicht ganz auf dem letzten Stand.

In den Papern P0732, P1185 und nun P1907 wurde die ganze Sache gerade 
gezogen, leider mit dem Ergebnis, dass die Typen der NTTP sog. 
structural sein müssen, was wiederum bedeutet, dass alle Datenelemente 
public sein müssen. Das finde ich schade, weil bspw. auch 
std::chrono::duration damit herausfällt (und auch einige meiner eigenen 
Klassentemplates).
1
#include <cstdint>
2
#include <cstdlib>
3
#include <type_traits>
4
#include <chrono>
5
#if __has_include("compare")
6
# include <compare> 
7
#endif
8
9
template<auto V> struct A{};
10
11
#if (__GNUC__ <= 9)
12
struct B {
13
    constexpr explicit B(int a) : value{a} {}
14
private:
15
    const int value{0};
16
};
17
#endif
18
19
#if (__GNUC__ > 9)
20
struct B {
21
    constexpr explicit B(int a) : value{a} {}
22
    constexpr auto operator<=>(const B&) const = default;
23
    // to be structural all members have to be public and structural as well
24
//private:
25
    const int value{0};
26
};
27
#endif
28
29
int main() {
30
    A<B{0x0042}> a1;
31
    A<B{0x0042}> a2;
32
    A<B{0x0815}> a3;
33
34
    static_assert(std::is_same_v<decltype(a1), decltype(a2)>);
35
    static_assert(!std::is_same_v<decltype(a1), decltype(a3)>);
36
    
37
    using namespace std::literals::chrono_literals;
38
    
39
//    A<1min> a4; // not possible
40
}

von svedisk ficklampa (Gast)


Lesenswert?

> Das finde ich schade

Das macht doch nuex, solange das gute C noch da ist.

von Guest (Gast)


Lesenswert?

Ich warte ja noch bis jemand eine Sprache in C++ einbettet die 
Turing-complete die Generierung von C++ - Code erlaubt.
Oder geht das mit Templates jetzt schon ;-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Guest schrieb:
> Oder geht das mit Templates jetzt schon ;-)

Templates für sich genommen sind Turing-vollständig.

Macht die Sprache(n) aber auch nicht schöner.

von Wilhelm M. (wimalopaan)


Lesenswert?

Guest schrieb:
> Ich warte ja noch bis jemand eine Sprache in C++ einbettet die
> Turing-complete die Generierung von C++ - Code erlaubt.

Der Beweis:

http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=0BB30D6BBA62A9F8054337264062C075?doi=10.1.1.14.3670&rep=rep1&type=pdf

Das template-Subsystem formt eine compile-time funktionale Sprache. 
Damit kann man Abbildungen (Funktionen) der Formen:

1) compile-time-constant -> compile-time-constant
2) compile-time-constant -> type
3) type -> compile-time-constant
4) type -> type

durchführen. Wobei man für 1) ganz einfach auch constexpr / consteval 
"normale" Funktionen benutzen kann/sollte. Boost-Hana als 
Meta-Programm-Bibliothek erledigt auch 2) - 3) mit constexpr-Funktionen.

von Heiko L. (zer0)


Lesenswert?

1
2.Attempt to develop the technology required for compiler and linkers to verify thatuser-defined equality operators are self-consistent and evaluate them, or3.Only allow non-type template parameters of class type for classes which havememberwise equality
2
If a template argument is a value of class type, then how do we mangle it into symbolnames? If we cannot, then how does the linker tell whether two template arguments ofclass type are the same? By default, class types do not even have a notion of equality.If we disregard unions, we could say that classes are simply compared memberwise for the purposes of template instantiation. However, doing this would break the invariant that &i<a> == &i<b> if and only if a == b : the latter may not even be valid, and if it is then it would only give the same results as the former if the relevant operator== implemented the same memberwise comparison that we used for the purposes of template instantiation.To resolve this question, we must either:
3
1.Allow the existing invariant to be broken, and accept the complexity and subtletiesadded to the language by doing this, or
4
2.Attempt to develop the technology required for compiler and linkers to verify that user-defined equality operators are self-consistent and evaluate them, or
5
3.Only allow non-type template parameters of class type for classes which have memberwise equality
6
7
This paper proposes pursuing the last of these options...

Ich kann nicht sagen, dass ich das nachvollziehen könnte.
Was spricht gegen das naive "constexpr operator==, wenn der nicht 
richtig funktioniert ist es halt UB"?

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Heiko L. schrieb:
> Was spricht gegen das naive "constexpr operator==, wenn der nicht
> richtig funktioniert ist es halt UB"?

Gott bewahre: nicht noch mehr davon!

Ich bin kein Compilerbauer und ich habe großen Respekt vor diesen Mädels 
und Jungs. Deswegen ist meine Antwort hier nur laienhaft:

1) Das bisherige Modell der getrennten Übersetzungseinheiten soll 
beibehalten werden

2) Aus 1) folgt, dass der Linker template-ids vergleichen können muss.

3) Für 2) wird bei NTTP deren Bit-Repräsentation als Wert in die 
template-id verwurschtelt (mangled)

4) Die Bit-Repräsentation eines class-type NTTP ist Summe der 
Bit-Repräsentationen der member.

5) Das ist identisch mit einer Gleichheitsdefinition von class-type 
NTTP, die auf allen ihren membern basiert.

6) Ein op== müsste dazu auf jeden Fall dazu konsistent implementiert 
werden.

7) Man kann 6) für user-defined op= nicht sicher stellen

8) Daher erzwingt man 6) durch den Verzicht auf Klasseninvarianten durch 
all-public member, d.h. der beobachtbare Zustand eines Typs sind alle(!) 
member, daher ist die Gleichheit zweiter Objekte durch einen 
elementweisen Vergleich gegeben.

Bottom-line: man bräuchte eine konsistente Abbildung des Objektzustandes 
(Werte) in eine template-id. Dazu ist für C++23 ein "operator template" 
vorgeschlagen. Wie man für den dann allerdings die Konsistenz mit op== 
bzw. op<=> sicherstellen will, ist mir noch nicht klar. Man läuft dann 
in dasselbe Problem wie bei Java mit equals() und hashCode().

Das ist eine "Lösung", die eben bestimmte Typen ausschließt, aber 
ansonsten in das bisherige Modell passt, ohne neue Schwierigkeiten 
einzubauen.

von Heiko L. (zer0)


Lesenswert?

Wilhelm M. schrieb:
> Das ist eine "Lösung", die eben bestimmte Typen ausschließt, aber
> ansonsten in das bisherige Modell passt, ohne neue Schwierigkeiten
> einzubauen.

Naja, enttäuschend ist das Ergebnis aber schon. Unter den 
Einschränkungen ist das Feature schon fast nicht zu gebrauchen.
Vielleicht hätte man deswegen von vornherein darauf verzichten und alles 
von Anfang an nur über den operator regeln. Das ganze Problem wäre dann 
nur syntactic sugar. Statt zu schreiben someClass<template_hash(x)> 
hätte man someClass<x> und könnte alles frei überladen.

bottom-line: Das "Feature" werde ich vermutlich nicht nutzen, bis es 
richtig funktioniert, so mit normalen Klassen und so.

Aber danke für die Erklärung.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Heiko L. schrieb:
> bottom-line: Das "Feature" werde ich vermutlich nicht nutzen, bis es
> richtig funktioniert, so mit normalen Klassen und so.

Na, so schlimm ist es auch wieder nicht: es sind dann einfach Typen ohne 
Klasseninvarianten bzw. immutables.

Vieles davon könnte man ersetzen durch constexpr-Funktionsparameter. 
Auch dazu gibt es einen Vorschlag.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.