Floating point concept für templates
-
Versuchs mal mit boost.type_traits und static_assert.
-
SeppJ schrieb:
Darf ich allgemein fragen: Warum? Was hast du gegen long double und meine eigene super tolle Fließkommaklasse?
Nichts Wirksames :p Ne ernsthaft, von mir aus dürfen die es auch gern sein, ich möchte nur sicherstellen, dass
Treelle Zahlen darstellen kann und kein Ganzzahl-Typ oder gar komplex o.ä. ist.GorbGorb schrieb:
Versuchs mal mit boost.type_traits und static_assert.
Kannst du mir vielleicht ein kleines Beispiel geben wie ich das konkret zusammenbauen muss?
Grüße
-
enable_if, ansonsten static_assert, wenn vorhanden.
-
berndbernd schrieb:
SeppJ schrieb:
Darf ich allgemein fragen: Warum? Was hast du gegen long double und meine eigene super tolle Fließkommaklasse?
Nichts Wirksames :p Ne ernsthaft, von mir aus dürfen die es auch gern sein, ich möchte nur sicherstellen, dass
Treelle Zahlen darstellen kann und kein Ganzzahl-Typ oder gar komplex o.ä. ist.GorbGorb schrieb:
Versuchs mal mit boost.type_traits und static_assert.
Kannst du mir vielleicht ein kleines Beispiel geben wie ich das konkret zusammenbauen muss?
Grüße
Naja generell sieht das ungefähr so aus:
static_assert( type_trait< T >::value , "error" );Wie genau der type_trait für deinen Fall heißt, weiß ich nicht auswendig, aber das findest du raus

-
template<typename T> struct IsFloat { static bool const value = false; }; template<> struct IsFloat<float> { static bool const value = true; } template<> struct IsFloat<double> { static bool const value = true; } template<> struct IsFloat<long double> { static bool const value = true; } template<typename T> T MyFunction(T bla) { static_assert(IsFloat<T>::value, "T is not float !"); return bla; } int main(int argc, char** argv) { MyFunction(1234); MyFunction(12.4); }
-
Ich meine mich erinnern zu können, dass es dafür schon einen type-trait im neuen C++11 Header <type_traits> gibt.
-
std::is_floating_point, gibts auch in Boost.TypeTraits.
-
Danke euch allen. Habs jetzt so gelöst:
BOOST_STATIC_ASSERT(boost::is_floating_point<T>::value);
-
berndbernd schrieb:
Danke euch allen. Habs jetzt so gelöst:
BOOST_STATIC_ASSERT(boost::is_floating_point<T>::value);Hallo Bernd,
der Nachteil von einem STATIC_ASSERT ist, dass im Falle eines Compilefehlers, dieser nur den Ort des STATIC_ASSERT angibt und nicht den Ort wo z.B. die Funktin mit dem unerwünschten Typen aufgerufen wird. Besser ist deshalb der Einsatz von boost.enable_if. In Deinem Fall etwa so:
#include <boost/type_traits/is_floating_point.hpp> #include <boost/utility/enable_if.hpp> template<class T> typename boost::enable_if< boost::is_floating_point< T >, void >::type // Bem.: void kann man auch weglassen, da Defaulttyp foo(T arg) { // don't compile if T neither float nor double } int main() { using namespace std; foo( 3. ); // ok foo( 3 ); // liefert 'Failed to specialize function template' mit Fehler in DIESER Zeile return 0; }Gruß
Werner
-
Ich hatte mal irgendwo ein nettes Makro für C++11 gesehen:
#include <type_traits> #define REQUIRES(...) ,class=typename std::enable_if<(__VA_ARGS__)>::type template<class T REQUIRES( std::is_floating_point<T>::value ) > void foo(T x);Das funzt, weil in C++11 Funktionstemplates Default-Template-Parameter haben dürfen. Allerdings klappt das nicht mehr mit Variadischen Templates, glaube ich.
Es wäre ja auch nur praktisch gewesen, wenn C++11 so etwas direkt unterstützt hätte *seufz*. Ich bin mal gespannt, (ob) was aus dem Concept-C++-Lager noch kommen wird.
-
Werner Salomon schrieb:
berndbernd schrieb:
Danke euch allen. Habs jetzt so gelöst:
BOOST_STATIC_ASSERT(boost::is_floating_point<T>::value);Hallo Bernd,
der Nachteil von einem STATIC_ASSERT ist, dass im Falle eines Compilefehlers, dieser nur den Ort des STATIC_ASSERT angibt und nicht den Ort wo z.B. die Funktin mit dem unerwünschten Typen aufgerufen wird. Besser ist deshalb der Einsatz von boost.enable_if. In Deinem Fall etwa so:
#include <boost/type_traits/is_floating_point.hpp> #include <boost/utility/enable_if.hpp> template<class T> typename boost::enable_if< boost::is_floating_point< T >, void >::type // Bem.: void kann man auch weglassen, da Defaulttyp foo(T arg) { // don't compile if T neither float nor double } int main() { using namespace std; foo( 3. ); // ok foo( 3 ); // liefert 'Failed to specialize function template' mit Fehler in DIESER Zeile return 0; }Gruß
WernerDas ist natürlich ein gutes Argument. Gibt es in ähnlicher Weise auch eine Möglichkeit, das Concept auf eine Klasse und nicht nur eine Funktion zu beziehen?
Grüße
-
berndbernd schrieb:
Gibt es in ähnlicher Weise auch eine Möglichkeit, das Concept auf eine Klasse und nicht nur eine Funktion zu beziehen?
http://www.boost.org/doc/libs/1_47_0/libs/utility/enable_if.html#htoc6
-
berndbernd schrieb:
Das ist natürlich ein gutes Argument. Gibt es in ähnlicher Weise auch eine Möglichkeit, das Concept auf eine Klasse und nicht nur eine Funktion zu beziehen?
Ja ..
Werner Salomon schrieb:
Besser ist deshalb der Einsatz von boost.enable_if.
folge dem Link
und lese das Kapitel '3.1 Enabling template class specializations'
-
krümelkacker schrieb:
Ich hatte mal irgendwo ein nettes Makro für C++11 gesehen:
#include <type_traits> #define REQUIRES(...) ,class=typename std::enable_if<(__VA_ARGS__)>::type template<class T REQUIRES( std::is_floating_point<T>::value ) > void foo(T x);Das funzt, weil in C++11 Funktionstemplates Default-Template-Parameter haben dürfen. Allerdings klappt das nicht mehr mit Variadischen Templates, glaube ich.
Sehr interessant. Damit könnte man enable_if auch für Konvertierungsoperatoren benutzen. Bei einer (oberflächlichen) Suche nach Regeln, die dieses Konstrukt im Zusammenhang mit Funktionsparameterpacks verbieten, habe ich erst einmal nichts gefunden.
-
Werner Salomon schrieb:
folge dem Link
und lese das Kapitel '3.1 Enabling template class specializations'Ah, da war ich schon mal
Habs irgendwie beim ersten Mal nicht geblickt.Sehe ich das richtig, dass ich auf alle Fälle eine Standard-Template-Deklaration brauche und dann halt die Spezialisierung mit dem enable_if für Floatingpoint-Typen - selbst wenn es die Klasse ausschließlich für Floatingpoint-Typen geben soll?
Grüße
-
Werner Salomon schrieb:
der Nachteil von einem STATIC_ASSERT ist, dass im Falle eines Compilefehlers, dieser nur den Ort des STATIC_ASSERT angibt und nicht den Ort wo z.B. die Funktin mit dem unerwünschten Typen aufgerufen wird. Besser ist deshalb (...)
Ach, das kommt auf den Compiler drauf an:
-
Bei Templates ist es doch üblich, dass die Instanziierungshierarchie aufgelistet wird, daher sind entsprechende Fehlermeldungen ja auch oft so lang.
An
enable_ifstört mich, dass die Schnittstelle unübersichtlich wird (ist z.B. für Doxygen problematisch). DasREQUIRES-Makro sieht jedoch interessant aus...
-
Nexus schrieb:
An
enable_ifstört mich, dass die Schnittstelle unübersichtlich wirdJa, mich auch.
Wenn man nur ne Fehlermeldung will finde ich
static_assert()gut. Kommt IMO einfach drauf an was man will/braucht.
Also ob es sofort ne Fehlermeldung geben soll, oder andere Overloads berücksichtigt werden sollen (SFINAE halt).Und so lange ich mir nicht sicher bin was die bessere Variante ist, tendiere ich zu
static_assert(), da man damit schneller ne Fehlermeldung bekommt. Und das ist IMO immer gut, wenn man was macht, was nicht vorgesehen war (und es kann nicht gut vorgesehen gewesen sein, wenn man sich nicht sicher war ob man SFINAE braucht oder nicht).BTW: auch MSVC 10 gibt mit
static_assert()ne brauchbare Fehlermeldung aus:1>vc10test.cpp(7): error C2338: will floating point!!!11elf 1> vc10test.cpp(13) : see reference to function template instantiation 'void foo<int>(T)' being compiled 1> with 1> [ 1> T=int 1> ]
-
berndbernd schrieb:
Sehe ich das richtig, dass ich auf alle Fälle eine Standard-Template-Deklaration brauche und dann halt die Spezialisierung mit dem enable_if für Floatingpoint-Typen - selbst wenn es die Klasse ausschließlich für Floatingpoint-Typen geben soll?
So ist es in der Hilfe beschrieben. Wobei ich nicht ausschließen will, dass es noch andere Lösungen gibt.
In Deinem Fall sähe es wohl so aus:#include <boost/type_traits/is_floating_point.hpp> #include <boost/utility/enable_if.hpp> template< typename T, typename Enable = void > struct Foo; // undefined struct template< typename T > struct Foo< T, typename boost::enable_if< boost::is_floating_point< T > >::type > { // ... hier kommt die Implementierung von Foo<T> }; int main() { Foo< double > d; Foo< int > i; // <== Compilefehler: 'i' uses undefined struct 'Foo<T>' return 0; }Gruß
Werner