2016-05-30 5 views
1

Ich habe eine Menge von C-Struktur, die Zähler darstellen. Diese Strukturen bestehen aus mehreren Mitgliedern des gleichen Typs, sagen wir uint64_t. Im Programm habe ich mehrere Instanzen der gleichen Struktur und in einigen Fällen muss ich alle diese gleiche Struktur summieren. Ich möchte operator+ dafür nicht verwenden, weil die Strukturen in Zukunft ändern können und mehr oder weniger Mitglieder haben und ich den Operator auch nicht immer ändern möchte.Sum alle Strukturelemente in generischer Weise

Ich dachte, dass ich eine sizeof verwenden und ein Array des Strukturtyps der Struktur aus der Struktur erstellen und dann das Array summieren könnte. Ich würde eine Vereinigung dieser Struktur und eines Arrays machen. Dies würde mein Problem lösen, den Operator nicht ändern zu wollen, wenn ein neues Mitglied hinzugefügt oder entfernt wird, aber dies würde nur funktionieren, solange die Struktur nur Mitglieder des gleichen Typs enthält.

Also vielleicht gibt es einige generische, Template-Methode, dies zu tun, aber ich bin nicht so gut mit Vorlagen, so frage ich Sie C++ Gurus um Hilfe.

Beispiel einer solchen Struktur:

struct counter{ 
    uint64_t a; 
    uint64_t b; 
    uint64_t c; 
    uint64_t d; 
    uint64_t e; 
}; 
+2

Kurz: Überqueren Sie die Struktur als Folge von benachbarten Speicherzellen und Summe entlang des Weges. Verwenden Sie sizeof, um zu bestimmen, wie viele Mitglieder Sie haben (vorausgesetzt, alle haben die gleiche Größe). Einige Zeiger und eine Schleife werden den Job erledigen. – Artur

+1

Ein großes Problem besteht darin, dass es dem Compiler freisteht, zwischen den Elementen oder am Ende der Struktur einen Padding einzufügen. Obwohl es unwahrscheinlich ist, dass die Struktur in der Frage angezeigt wird, ist es nicht möglich, sie für irgendeine Struktur generisch zu machen, besonders wenn Sie mit dem Mischen von Typen beginnen. Sie müssen auch vorsichtig sein, das strenge Aliasing zu brechen. –

+4

Modifizierung von 'Operator +', wenn die Struktur ändert, wäre die sinnvolle Sache zu tun. – jrok

Antwort

2

nicht der beste Weg, sondern eine Möglichkeit, die Funktionalität, die Sie brauchen, um zu erreichen ist:

/* counter.xh */ 
COUNTER_MEMBER(uint64_t, a); 
COUNTER_MEMBER(uint64_t, b); 
COUNTER_MEMBER(uint64_t, c); 
COUNTER_MEMBER(uint64_t, d); 
COUNTER_MEMBER(uint64_t, e); 

Dann in einigen Header:

/* counter.h */ 

struct counter{ 
#define COUNTER_MEMBER(TYPE,NAME) TYPE NAME; 
    #include "counter.xh" 
}; 

Jetzt kommt die Add-Funktion:

/* foo.cpp */ 
uint64_t add_members(const counter &obj) { 
    uint64_t sum = 0LLU; 
#define COUNTER_MEMBER(TYPE,NAME) sum += obj.NAME; 
#include "counter.xh" 
    return sum; /* I hope there was no overflow */ 
} 

Live example

+0

Und diese Technik heißt [X-Macros] (https: //en.wikipedia.org/wiki/X_Macro), nicht wahr? Zumindest glaube ich, dass das einer der Namen dafür ist. –

+0

@ JonathanLeffler Ja, es heißt X-Makro. –

+1

Ich habe diese Lösung akzeptiert, weil sie mir am allgemeinsten erscheint und sehr einfach zu pflegen ist. – Jan

0

Ich denke, das nicht die beste Lösung ist, aber es kann eine nützliche Methode sein. Wenn struct Counter mehr oder weniger Mitglieder haben, ändere ich GetSumOfAll() Funktion nur.

struct Counter 
{ 
    uint64_t a; 
    uint64_t b; 
    uint64_t c; 
    uint64_t d; 
    uint64_t e; 
}; 
typedef std::vector<Counter> VecCounter; 

uint64_t GetSumOfMember(const VecCounter& vec, uint64_t Counter::*member) 
{ 
    uint64_t sum = 0; 

    std::for_each(vec.begin(), vec.end(), [&](const Counter& counter) 
    { 
     sum += counter.*member; 
    }); 

    return sum; 
} 

uint64_t GetSumOfAll(const VecCounter& vec) 
{ 
    uint64_t sumA = GetSumOfMember(vec, &Counter::a); 
    uint64_t sumB = GetSumOfMember(vec, &Counter::b); 
    uint64_t sumC = GetSumOfMember(vec, &Counter::c); 
    uint64_t sumD = GetSumOfMember(vec, &Counter::d); 
    uint64_t sumE = GetSumOfMember(vec, &Counter::e); 

    return sumA + sumB + sumC + sumD + sumE; 
} 

int main() 
{ 
    VecCounter v{ { 1, 2, 3, 4, 5 }, { 2, 3, 4, 5, 6 } }; 
    uint64_t sum = GetSumOfAll(v); 

    return 0; 
} 
+0

Bevor Sie all diese Metaprogrammierung vorschlagen, würde ich Ihnen dringend empfehlen, die Disassemblierung anzusehen und zu sehen, woraus sie tatsächlich resultiert. 'G ++ -std = C++ 11 -O3 erzeugt ein unnötig kompliziertes Programm für solch eine einfache Aufgabe. – Lundin