2015-09-25 10 views
5

Ich baue eine dynamische Animation & Rendering-System und ich würde gerne Boost.Units für die Darstellung von physikalischen Größen verwenden, um die schöne dimensionale Sicherheit zu bekommen. Allerdings werde ich Arrays von Mengen um auf Funktionen übergeben müssen, die nichts über Boost-wissen, wie:Wie tippt man das Wort-Boost Quantität Arrays auf den zugrunde liegenden Typ?

  • OpenGL Puffer füllende Befehle. Diese nehmen einfach eine const void * und erwarten, ein Array von entweder float oder double Werte bei der Dereferenzierung zu finden. Sie lesen die Daten.

  • Lineare Algebra-Funktionen (wie gemm oder gesv) aus verschiedenen Implementierungen von BLAS und LAPACK. Diese nehmen im Allgemeinen entweder eine float * oder double * zu einer gegebenen Anordnung. Sie lesen und schreiben die Daten.

Ich weiß, dass boost::units::quantity<U, T> ein const T& value() Mitglied hat, die den Zugang zu den enthaltenen T Wert direkten Bezug gibt. Ich habe auch verifiziert, dass eine boost::units::quantity<U, T> eine Standard-Layout-Struktur mit genau einem nicht statischen Datenelement vom Typ T ist.

wir also, dass ein boost::units::quantity<U, T> q für nehmen, folgendes gilt:

  • static_cast<const void*>(&q) == static_cast<const void*>(&q.value())
  • sizeof(q) == sizeof(T)

Meine Frage ist: Da ein Array boost::units::quantity<U, T> a[100];, ist es sicher zu:

  1. Übergeben Sie &a[0].value() an eine Funktion, die erwartet, ein Array von 100 Objekten des Typs T an der Adresse zu lesen?

  2. Übergeben Sie reinterpret_cast<T*>(&a[0]) an eine Funktion, die 100 sequenzielle Werte des Typs T an die Adresse schreibt?

Ich bin mir sehr wohl bewusst ist dies wahrscheinlich nicht definiertes Verhalten ist, aber jetzt muss ich (1) Prinzip der „Praktikabilität schlägt Reinheit“ folgen. Selbst wenn dies UB ist, wird es die erwartete Sache tun, oder wird es auf unvorhergesehene Weise beißen? Da dies Compiler-spezifisch sein könnte: Ich brauche das für moderne MSVC (ab VS 2015).

Und wenn das nicht sicher ist, gibt es eine Möglichkeit, dies sicher zu tun? "This" bezieht sich auf "Boost.Units mit OpenGL und mit Number Crunchers, die nur eine C-Schnittstelle haben", ohne unnötig Daten kopieren.


(1) vom Zen of Python angepasst sind.

+0

Ich denke, wo Sie sagen UB Sie IB bedeuten? Weil niemand UB jemals abschlagen sollte. – sehe

Antwort

2

Ja, das sieht nach etwas aus, was Sie tun können.

Es gibt eine Sache, die Sie nicht erwähnt haben und die zur Liste der zu überprüfenden Bedingungen hinzugefügt werden sollte: Die Ausrichtung des umschlossenen Betragstyps sollte mit der des zugrunde liegenden Typs übereinstimmen. (siehe alignof).

Also würde ich in der Praxis Code nur mit einer Anzahl von static_asserts¹ schreiben, die die Annahmen schützen, die die Neuinterpretation gültig machen.

Wenn Sie die Behauptung hinzufügen, dass T dasselbe ist wie remove_cv_t<decltype(q.value())>, sollte dies zuverlässig sein.

Mit diesen Vorwarnungen sollte es nicht UB geben, nur IB (Implementierung definiertes Verhalten) aufgrund der Semantik von reinterpret_cast auf Ihrer speziellen Plattform.

¹ und vielleicht die debug behaupten, dass &q.value() == &q

+1

Aber die strenge Aliasing-Regel verletzt ist UB, nicht IB. (Es ist verletzt in den Funktionen genannt, das heißt, BLAS/LAPACK/OpenGL C-Code verletzt es.) – dyp

+0

Mmm. Da ist dieser Aspekt. Ich weiß nicht, ob das notwendigerweise ein Problem ist, aber es ist sicherlich ein Bereich, in den man sich vertiefen sollte. – sehe

+0

@dyp Auch das strikte Aliasing war mein Anliegen. Gleichzeitig ist * tatsächlich ein Objekt vom Typ float an dieser Adresse (als Unterobjekt des vollständigen Objekts vom Typ menge). Vielleicht wird deswegen das strenge Aliasing nicht verletzt? – Angew