Filter the types that get fallback lexical conversion operators
authorMikko Rasa <tdb@tdb.fi>
Sat, 1 Dec 2012 20:50:39 +0000 (22:50 +0200)
committerMikko Rasa <tdb@tdb.fi>
Sat, 1 Dec 2012 20:56:39 +0000 (22:56 +0200)
Only enable the operators for types that already have iostream formatting
operators defined.  Having them exist for everything would interfere with
some other stuff I'm going to commit in a moment.

source/core/meta.h
source/strings/lexicalcast.h

index 0034512b6ec2bea573ffbcc34115fc8562a5cac8..923096517dba8132a873de68a79344ab6e2910b1 100644 (file)
@@ -11,6 +11,7 @@ template<typename T>
 struct RemoveConst<const T>
 { typedef T Type; };
 
+
 template<typename T>
 struct RemoveReference
 { typedef T Type; };
@@ -19,6 +20,34 @@ template<typename T>
 struct RemoveReference<T &>
 { typedef T Type; };
 
+
+template<bool c, typename R>
+struct EnableIf;
+
+template<typename R>
+struct EnableIf<true, R>
+{ typedef R Yes; };
+
+template<typename R>
+struct EnableIf<false, R>
+{ typedef R No; };
+
+
+/**
+Common fragments used in SFINAE-based decider constructs.
+*/
+struct Sfinae
+{
+       struct Yes { char c[2]; };
+       struct No { char c; };
+
+       template<size_t s>
+       struct Evaluate
+       {
+               enum { value = (s==sizeof(Yes)) };
+       };
+};
+
 } // namespace Msp
 
 #endif
index c6a17da3491d053b6460399fddea6473ea1ca839..80963f44dd3a233ff2d16b01ec007935d01e73c9 100644 (file)
@@ -4,6 +4,7 @@
 #include <sstream>
 #include <string>
 #include <stdexcept>
+#include <msp/core/meta.h>
 #include "fmt.h"
 
 namespace Msp {
@@ -89,7 +90,39 @@ void operator>>(const LexicalConverter &, std::string &);
 // Generic operators using stringstream
 
 template<typename T>
-void operator<<(LexicalConverter &c, const T &v)
+struct HasFormattedOutput: Sfinae
+{
+       static std::ostream &s;
+       static T &v;
+
+       /* The expression must depend on the template parameter, or the compiler
+       will give an error. */
+       template<typename U>
+       static Yes f(int (*)[sizeof(s<<HasFormattedOutput<U>::v)]);
+       template<typename U>
+       static No f(...);
+
+       enum { value = Evaluate<sizeof(f<T>(0))>::value };
+};
+
+template<typename T>
+struct HasFormattedInput: Sfinae
+{
+       static std::istream &s;
+       static T &v;
+
+       template<typename U>
+       static Yes f(int (*)[sizeof(s>>HasFormattedOutput<U>::v)]);
+       template<typename U>
+       static No f(...);
+
+       enum { value = Evaluate<sizeof(f<T>(0))>::value };
+};
+
+
+template<typename T>
+typename EnableIf<HasFormattedOutput<T>::value, void>::Yes
+operator<<(LexicalConverter &c, const T &v)
 {
        std::ostringstream ss;
        ss<<c.get_fmt()<<v;
@@ -97,7 +130,8 @@ void operator<<(LexicalConverter &c, const T &v)
 }
 
 template<typename T>
-void operator>>(const LexicalConverter &c, T &v)
+typename EnableIf<HasFormattedInput<T>::value, void>::Yes
+operator>>(const LexicalConverter &c, T &v)
 {
        std::istringstream ss(c.get());
        ss.setf(std::ios_base::fmtflags(0), std::ios_base::skipws);