2013-06-07 9 views
16

Dieses Problem wurde ein paar Mal diskutiert, aber alle Lösungen, die ich gefunden habe, funktionierten entweder nicht oder basierten auf der statischen Behauptung von Boost. Mein Problem ist einfach. Ich habe eine Klasse und möchte nur echte Typen zulassen (Double und Float). Ich möchte einen Fehler bei der Kompilierung, wenn ich versuche, die Klasse mit einem anderen Typ als float oder double zu instanziieren. Ich benutze Visual C++ 11. Hier ist was ich versucht habe:Wie schränke ich eine Vorlagenklasse auf bestimmte integrierte Typen ein?

template <typename RealType> 
class A 
{ 
    // Warning C4346 
    static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value); 
} 


template <typename RealType> 
class A 
{ 
    // Error C2062: type 'unknown' unexpected 
    static_assert(decltype(RealType) == double || decltype(RealType) == float); 
} 

Irgendwelche Ideen? Danke im Voraus!

+1

Die erste Frage ist, ist es wichtig? Wenn Sie die Vorlage mit einem anderen Typ instanziieren und der Typ nicht so behandelt werden kann, wie es die Vorlage erwartet, schlägt die Kompilierung fehl. Und wenn es möglich ist, erlaubt * nur * diese beiden Arten effektiv zu verbieten ... sagen ... einen Typ wie BigDecimal. – cHao

+0

Visual Studio wirklich eine Warnung ausgeben, wenn static_assert fehlschlägt, und kein Fehler? Klingt wie ein Fehler. –

+0

Siehe auch [C++ - Vorlagen, die nur bestimmte Typen akzeptieren] (http://stackoverflow.com/q/874298/) und [C++ - Vorlagenparameter auf Unterklasse beschränken] (http://stackoverflow.com/q/3175219).Sie sind älter als C++ 11, aber sie könnten ein guter Marker für jemand anderen sein. – jww

Antwort

12

Eine Lösung, die ich gesehen habe, ist std::enable_if in einem Typalias zu verwenden. Etwas wie:

using value_type = typename std::enable_if< 
        std::is_same<float, RealType>::value || 
        std::is_same<double, RealType>::value, 
        RealType 
       >::type; 

value_type besteht nur, wenn RealType genau float oder double. Andernfalls ist der Typ nicht definiert und die Kompilierung schlägt fehl.

Ich warnte jedoch davor, mit Typen zu streng zu sein. Vorlagen sind so leistungsfähig wie sie sind, zum Teil, weil die Duck Typisierung, die sie tun, bedeutet, dass jeder Typ, der verwendet werden kann, wie Sie es verwenden möchten, funktioniert. Das Ablehnen von Typen, um Typen zu verbieten, gewinnt im Allgemeinen nicht viel und kann Dinge weniger flexibel machen, als sie sein könnten. Beispielsweise können Sie einen Typ mit höherer Genauigkeit nicht verwenden, z. B. einen Dezimaltyp.

+0

Das, und wenn Sie nur zwei Spezialisierungen benötigen, könnte gute alte OO und Laufzeit-Polymorphie eine bessere Idee sein (zumindest eine Überlegung wert). –

+0

SFINAE ist wirklich gut, wenn Sie später weitere Spezialisierungen des Templates erstellen wollen :) Wenn jedoch sicher ist, dass es keine andere Spezialisierung geben wird, erlaubt 'static_assert' die Anzeige von aussagekräftigen Fehlermeldungen (weil SFINAEs oft meine Augen schmerzen). – Morwenn

26

In Ihrem ersten Beispiel static_assert sollte einen zweiten Parameter nehmen, die ein Zeichenfolgenliteral, sonst ist es als wären zum Scheitern verurteilt (edit: die der zweite Parameter ist legal, da C++ 17 fallen). Und dieses zweite Argument kann nicht voreingestellt werden.

Ihr zweites Beispiel ist aus mehreren Gründen falsch:

  • decltype ist auf einem Ausdruck verwendet werden, nicht auf einen Typ.
  • Sie können einfach nicht Typen mit == vergleichen, der richtige Weg, dies zu tun ist, was Sie in Ihrem ersten Versuch mit std::is_same versuchen.

also der richtige Weg zu tun, was Sie versuchen zu erreichen ist:

#include <type_traits> 

template <typename RealType> 
class A 
{ 
    static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value, 
       "some meaningful error message"); 
}; 

Außerdem, ich wette, Sie versuchen, Ihre Vorlage Gleitpunkte Werte zu verengen.

#include <type_traits> 

template <typename RealType> 
class A 
{ 
    static_assert(std::is_floating_point<RealType>::value, 
       "class A can only be instantiated with floating point types"); 
}; 

Und als Bonus, nehmen this online example: Um dies zu tun, können Sie das Merkmal std::is_floating_point verwenden.

5

Auf diese Weise erlaubt es auch Spezialisierung für verschiedene Arten:

template<typename T, typename Enable = void> 
class A { 
/// Maybe no code here or static_assert(false, "nice message"); 
}; 

/// This specialization is only enabled for double or float. 
template<typename T> 
class A<T, typename enable_if<is_same<T, double>::value || is_same<T, float>::value>::type> { 

}; 
+1

mit 'static_assert (false," nette Nachricht ");' das Programm ist schlecht gebildet, keine Diagnose erforderlich. Siehe http://stackoverflow.com/questions/30078818/static-assert-dependent-on-n-type-template-parameter-different-behavior-on-gc Das Problem sieht zunächst komplexer aus, aber die Unterstreichungsursache ist So einfach wie dein Beispiel. – bolov

Verwandte Themen