Variadic template expansion problem
-
@Hellhound ... Ich habe testweise auch mal Member in die "Container-Klasse" gepackt, die waren auch nicht erreichbar. Ich denke, das ist eher ein Fehler im Member-Lookup, weil das sizeof auch passt...
-
Ich korrigiere mich, das sizeof sieht auch merkwürdig aus.
-
Joar, es sieht so aus, dass der Compiler da überhaupt nicht expandiert, weil Sub kein Pack ist und erst wenn man das identity da reinklatscht, dann versucht er Classes zu expandieren.
sizeof(Foo<A,B,C>) ist 1...
-
...
-
Naja, der Fix steht ja da... Unschön, aber immerhin macht es nicht so viel Arbeit, wie ein komplettes Subsystem auszutauschen, weil irgendein neues Feature mit virtuellen Basisklassen clasht... Oder weil nullptr nicht konstant sein sollen...
-
@decimad:
Dank Deines Workarounds mit dem identity-template klappt das wunderbar.Ich bin schon mehrfach über das Problem gestoßen, dass ich eine Kern-klasse habe, nennen wir sie Core, für die ich ein Interface zum Zugriff auf ebendiese Kernfunktionen bereitstelle. Jetzt kommt es immer mal wieder vor, dass ich Core um weitere Funktionen erweitern möchte, die für sich zusammengefasst eine neue logische Gruppierung bilden, aber vom Umfang her es sich kaum lohnt, dafür ein neues zusätzliches Interface bereitzustellen. Jetzt könnte ich diese natürlich in Core und dem Interface für Core (nennen wir es ICore) mit aufnehmen. Dann könnte Core aber sehr schnell unübersichtlich werden.
Deshalb habe ich mir gedacht, wenn ich mir die Core-Klasse automatisch mit einem Template aus mehreren Unterklassen zusammenbauen lassen könnte, dass mir auch automatisch ein passendes Interface zur Verfügung stellt, wäre das für mich sehr übersichtlich und praktisch.Wenn ich als Bedingung ansetze, dass die Modulklassen, aus denen Core zusammengesetzt wird '::Interface' und '::Module' enthalten, kann ich mir das bei der Komposition der Coreklasse zunutze machen. Hier mal zwei Module als Beispiel:
struct A { class Interface { public: virtual void foo(void) = 0; }; class Module : public virtual Interface { public: virtual void foo(void) { std::cerr << "foo A\n"; } void foo2(void) {/*....*/} // Not accessible via Interface }; }; struct B { class Interface { public: virtual void bar(void) = 0; virtual void bar2(void) = 0; }; class Module : public virtual Interface { public: virtual void bar(void) { std::cerr << "bar B\n"; } virtual void bar2(void) { std::cerr << "bar2 B\n"; } }; };Jetzt baue ich mir automatisch eine Core-Klasse, die ein komplettes Interface zur Verfügung stellt zusammen:
// identity template from decimad (C++.de Forum) template<typename T> struct identity { using type = T; }; template<typename... MODULES> struct CoreModule { class Interface : virtual public identity<MODULES>::type::Interface... {}; class Module : public Interface, public identity<MODULES>::type::Module... {}; }; typedef CoreModule<A, B> CoreClass; typedef CoreClass::Interface ICore; typedef CoreClass::Module Core;Ich kann jetzt ein Objekt vom Typ 'Core' instanzieren und den restriktierten Zugriff über das komponierte Interface 'ICore' bereitstellen. 'Core' selbst ist auch kompatibel zu den jeweiligen Modul-Interfaces 'A::Interface' und 'B::Interface', falls man in einer Subroutine nur einen Zugriff auf Teile von Core zulassen möchte.
void test(ICore* core) { core->foo(); core->bar(); } void test2(A::Interface* a) { a->foo(); } int _tmain(int argc,_TCHAR* argv[]) { ICore* core = new Core(); test(core); test2(core); delete core; std::cin.get(); return 0; }
-
Ich würde Dir ans Herz legen, einen Weg zu finden, das ohne virtuelle Basisklassen umzusetzen, die meisten Fälle kann man seit Variadics auch mit "statischen" Funktionen umsetzen. Ich gebe den Ratschlag, denn Funktionszeiger als Template-Argumente, die man irgendwann einmal einsetzen möchte, weil mehrdeutige Interface-Funktionen einfach nur nerven, zu einem internen Compilerfehler führen.
-
Danke für den Hinweis.
-
In der Tat wäre ich eigentlich dafür, virtuelle Basisklassen aus dem Standard zu schmeißen, zumindest dann, wenn sie im Moment der einzige Grund dafür sind, dass offsetof nur bei POD-Typen funktioniert. Das hier wäre der ideale Einsatz für camper, der weiß da bestimmt mehr

-
Und ja, ich weiß, dann müsste man auch die Streams rausschmeißen: Ja, bitte, da habe ich in etwa dieselbe Meinung wie der Nichtmember in dem aktuellen anderen facet-Thread da...