Is it possible to define a data-member without [specializing] the whole template?
static
Daten Mitglieder einer Klasse Vorlage sind erlaubt explizit spezialisiert werden ([temp.expl.spec]), aber wenn Sie dies tun möchten, können Sie nicht bereits können einen Initialisierer für das Element festlegen, innerhalb die Klassenvorlage (class.static.data). Das heißt,
wenn wir ersetzen constexpr
mit const
, würde dieser Code in Ordnung sein:
template<int>
struct X {
static const int x;
};
template<int I>
const int X<I>::x = 0;
template<>
const int X<1>::x = 1;
Aber dieser Code würde NICHT in Ordnung sein:
template<int>
struct X {
static const int x = 0;
};
template<>
const int X<1>::x = 1;
Sie können sehen, der Unterschied ist, Wo initialisieren wir die Variable für die primäre Vorlage.
Wenn wir nun ersetzen const
mit constexpr
wollen, dann sind wir benötigt einen Initialisierer (class.static.data) zur Verfügung zu stellen:
A static
data member of literal type can be declared in the class definition with the constexpr
specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression
So wir in dieser seltsamen Situation enden, wo Wir können das static
Mitglied spezialisieren, aber nicht, wenn es constexpr
ist, weil constexpr
einen Initialisierer erfordert. IMHO ist das ein Manko des Standards.
Es scheint jedoch nicht, dass alle modernen Compiler zustimmen.
gcc 8.0.0 kompiliert (aber verlinkt) Ihren Code nicht, wie er ist (falsch), wenn Sie jedoch einen Initialisierer für die Spezialisierung hinzufügen, beschwert er sich über doppelte Initialisierung (rechts).
Klirren 6.0.0 lässt sich nicht kompilieren Sie den Code wie besehen (rechts), aber wenn man die initializer hinzufügen funktioniert es ohne Probleme (falsch, aber das ist wahrscheinlich das, was die Standard diktieren sollte)
MSVC 19.00.23506 kompiliert den Code nicht so wie er ist (rechts), UND er kompiliert den Code nicht, wenn Sie den Initialisierer hinzufügen (sich über die Neudefinition beschweren) (rechts).
Am Ende könnte es nur einfacher, die Spezialisierung in eine Helfer Traits Klasse zu drücken:
template<int>
struct X_Traits{
static constexpr int value = 0;
};
template<>
struct X_Traits<1>{
static constexpr int value = 1;
};
template<int I>
struct X {
static constexpr int x=X_Traits<I>::value;
// ...
};
In C++ 17 und darüber hinaus nutzen wir constexpr if machen zu vermeiden, benötigen Spezialisieren Sie unsere Traits Klasse:
template<int I>
struct X_Traits{
static constexpr int get_value(){
if constexpr(I==1){
return 1;
}else{
return 0;
}
}
};
template<int I>
struct X {
static constexpr int x=X_Traits<I>::get_value();
// ...
};
int main(){
static_assert(X<0>::x == 0);
static_assert(X<1>::x == 1);
}
Vielleicht sollte Ihre "Und" Frage die führende sein. – DeiDei
Ja, bearbeitet ;-) – wimalopaan