C ++ 11: Klassenmitglied in Mehrfachvererbung disambiguieren
Angenommen, ich habe diese variadische Basisklassenvorlage:
template <typename ... Types>
class Base
{
public:
// The member foo() can only be called when its template
// parameter is contained within the Types ... pack.
template <typename T>
typename std::enable_if<Contains<T, Types ...>::value>::type
foo() {
std::cout << "Base::foo()\n";
}
};
Dasfoo()
member kann nur aufgerufen werden, wenn sein Template-Parameter mit mindestens einem der Parameter von @ übereinstimBase
(Die Implementierung vonContains
ist unten in diesem Beitrag aufgeführt):
Base<int, char>().foo<int>(); // fine
Base<int, char>().foo<void>(); // error
Nun definiere ich eine abgeleitete Klasse, die zweimal von Base erbt, mit nicht überlappende Mengen von Typen:
struct Derived: public Base<int, char>,
public Base<double, void>
{};
Ich hatte gehofft, dass beim Aufruf von z. B.
Derived().foo<int>();
Der Compiler würde herausfinden, welche Basisklasse verwendet werden soll, da es sich um eine SFINAE-Klasse handelt, die @ nicht enthälint
. Sowohl GCC 4.9 als auch Clang 3.5 beschweren sich jedoch über einen mehrdeutigen Anruf.
Meine Frage ist dann zweifach:
Warum kann der Compiler diese Mehrdeutigkeit nicht beheben (allgemeines Interesse)?Was kann ich tun, um diese Arbeit zu machen, ohne schreiben zu müssenDerived().Base<int, char>::foo<int>();
? BEARBEITEN GuyGreer hat mir gezeigt, dass der Aufruf eindeutig ist, wenn ich zwei using-Deklarationen hinzufüge. Da ich jedoch die Basisklasse bereitstelle, von der der Benutzer erben kann, ist dies keine ideale Lösung. Ich möchte nicht, dass meine Benutzer diese Deklarationen (die für große Typlisten sehr ausführlich und sich wiederholend sein können) zu ihren abgeleiteten Klassen hinzufügen müssen, wenn dies überhaupt möglich isImplementierung vonContains
:
template <typename T, typename ... Pack>
struct Contains;
template <typename T>
struct Contains<T>: public std::false_type
{};
template <typename T, typename ... Pack>
struct Contains<T, T, Pack ...>: public std::true_type
{};
template <typename T, typename U, typename ... Pack>
struct Contains<T, U, Pack ...>: public Contains<T, Pack...>
{};