2016-05-11 10 views
6

Es scheint nicht möglich zu sein, einen Verweis auf die Basisklasse Objekt eines abgeleiteten Objekts als Template-Parameter übergeben, wie ich versuche, hier zu tun:nicht-type template-Parameter: wie Verweis auf Basisklassenobjekt übergeben?

struct a 
{ int _v; 
    constexpr a():_v(0){} 
    constexpr a(int v): _v(v){} 
}; 

struct c: public a 
{ constexpr c():a(){} 
    constexpr c(int v):a(v){} 
}; 

extern const c default_a; 

constexpr const c default_a { 1 }; 

const a& c_as_a = default_a; 
// ^-- this line (16) causes no error - c can be converted to a 

template < const a & The_A = default_a > 
struct b 
{ constexpr static const a &the_a = The_A; 
}; 

b<> a_b; 

// Template instantiation causes error: 
// t.C:24:7: error: could not convert template argument 'default_a' to 'const a&' 
// b<> a_b; 
// ^

ich die ‚c erwartet hätte 'Objekt ‚default_a‘, da es aus abgeleitet ist ‚a‘, akzeptabel zu sein als ‚eine & const‘, wie es auf der Linie 16.

Warum ist das nicht OK als Template-Parameter?

Welcher Abschnitt der Spezifikation schreibt dieses Verhalten eigentlich vor?

Vielleicht ist mein Build von gcc-5.3.0 irgendwie defekt?

Jemand gefunden eine gute Problemumgehung/Möglichkeit der Übergabe eines abgeleiteten Objekts als Referenz-Vorlage-Parameter des Basisklassenobjekts?

template < const a & The_A = c_as_a > 

tC:: 24: 7: Fehler: 'const ein & c_as_a' ist keine gültige Vorlage

Ich kann für 'default_a' in Template-Argument-Liste nicht nur die Bezugsgröße 'c_as_a' ersetzen Argument für Typ 'const a &', weil eine Referenzvariable keine konstante Adresse hat b <> a_b;

Ich kann auch nicht jeden constexpr Funktionsaufruf ersetzen, die wie etwas tut:

constexpr const a& c_as_a(const c &c){ return *reinterpret_cast<const a*>(&c);} 
... 
template < const a & The_A = c_as_a(default_a) > 

da dieser Aufruf kein ‚Objekt mit externer Bindung‘ ist.

Alle Vorschläge, wie man einen Verweis auf eine Basisklasse eines abgeleiteten Objekts als Template-Parameter übergeben würde sehr geschätzt - es ist hat möglich sein, ich kann einfach nicht sehen, wie ATM.

Es muss eine Möglichkeit geben, einen Verweis auf das Basisklassenobjekt eines Objekts als Vorlagenparameter anzugeben.

+0

in C++ 14 der nicht-Typ Template-Parameter 'const a &' nur direkt an einen benannten lvalue mit Bindung binden kann. Du hast also kein Glück. In C++ 17 wird es erlaubt, an einige weitere Dinge zu binden, [siehe hier] (http://en.cppreference.com/w/cpp/language/template_parameters) –

+0

Danke MM - Entschuldigung für die erste 'The_A = c Tippfehler - jetzt korrigiert. – JVD

+0

OK, danke für die Bestätigung, was ich vermutet habe. – JVD

Antwort

1

A gcc spezifische Abhilfe:

struct a 
{ int _v; 
    constexpr a():_v(0){} 
    constexpr a(int v): _v(v){} 
}; 

struct c: public a 
{ constexpr c():a(){} 
    constexpr c(int v):a(v){} 
}; 

extern const c _default_c; 

constexpr const c _default_c { 1 }; 

extern const a default_a; 

const a default_a __attribute__((alias("_default_c"))); 

template < const a & The_A = default_a > 
struct b 
{ constexpr static const a &the_a = The_A; 
}; 

b<> a_b; 

Die oben kompiliert OK.

Glücklicherweise wissen wir, dass der Name von '_default_c' nicht gemangelt wird.

0

Das Problem ist bei der Initialisierung eines const Verweis ein temporäres erstellt wird, und provisorische sind nicht zulässig mit Referenz-Initialisierung in diesem Kontext (konvertierte Konstante Ausdruck).

N4140 8.5.3 (5.2.2.1)

...

  • If T1 is a non-class type, a temporary of type "cv1T1 " is created and copy-initialized (8.5) from the initializer expression. The reference is then bound to the temporary.

In all cases except the last (i.e., creating and initializing a temporary from the initializer expression), the reference is said to bind directly to the initializer expression.

dann in 5.19:

A conditional-expressione is a core constant expression unless the evaluation of e , following the rules of the abstract machine (1.9), would evaluate one of the following expressions:

(2.9) - an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either

  • it is initialized with a constant expression or ...
+0

Aha! Danke für die Standard-Dokument Referenz Zitate - Ich werde weiter studieren. Ich freue mich auf C++ - 17 das sauber zu lösen - für jetzt wird mein GCC Hack tun. – JVD

+0

@JVD Ich kann die Sprache nicht finden, in der es direkt in N4140 "bindet direkt" sagt, aber es ist in der [neuesten Entwurf] (http://eel.is/c++draft/expr.const#4). Wird die Antwort später aktualisieren. – user6320913

+0

Leider ist alles, was man braucht, um das obige Fragment in einen umschließenden Namespace zu platzieren - dann wird der '_default_c' Name verändert. – JVD

0

Fix, die im Namensraum funktioniert:

namespace U { 
    struct a 
    { int _v; 
     constexpr a():_v(0){} 
     constexpr a(int v): _v(v){} 
    }; 

    struct c: public a 
    { constexpr c():a(){} 
     constexpr c(int v):a(v){} 
    }; 
    extern "C" { 
    extern const c _default_c; 

    constexpr const c _default_c { 1 }; 
    } 

    extern const a default_a; 

    const a default_a __attribute__((alias("_default_c"))); 

    template < const a & The_A = default_a > 
    struct b 
    { constexpr static const a &the_a = The_A; 
    }; 

    b<> a_b; 
} 
Verwandte Themen