← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 3141: sfinae fix for VS

 

------------------------------------------------------------
revno: 3141
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Fri 2012-11-23 20:35:18 +0100
message:
  sfinae fix for VS
modified:
  dcpp/Util.h
  test/testsfinae.cpp


--
lp:dcplusplus
https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk

Your team Dcplusplus-team is subscribed to branch lp:dcplusplus.
To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== modified file 'dcpp/Util.h'
--- dcpp/Util.h	2012-11-10 15:15:22 +0000
+++ dcpp/Util.h	2012-11-23 19:35:18 +0000
@@ -92,29 +92,20 @@
 template<typename T> double fraction(T a, T b) { return static_cast<double>(a) / b; }
 
 /** Uses SFINAE to determine whether a type provides a function; stores the result in "value".
-Inspired by <http://stackoverflow.com/a/8752988>. */
-#ifndef _MSC_VER
-#define HAS_FUNC(name, funcRet, funcTest) \
-	template<typename HAS_FUNC_T> struct name { \
-		typedef char yes[1]; \
-		typedef char no[2]; \
-		template<typename HAS_FUNC_U> static yes& check(HAS_FUNC_U* data, \
-			typename std::enable_if<std::is_same<funcRet, decltype(data->funcTest)>::value>::type* = nullptr); \
-		template<typename> static no& check(...); \
-		static const bool value = sizeof(check<HAS_FUNC_T>(nullptr)) == sizeof(yes); \
-	}
-#else
-/// @todo don't verify the return type of the function on MSVC as it fails for obscure reasons. recheck later...
-#define HAS_FUNC(name, funcRet, funcTest) \
-	template<typename HAS_FUNC_T> struct name { \
-		typedef char yes[1]; \
-		typedef char no[2]; \
-		template<typename HAS_FUNC_U> static yes& check(HAS_FUNC_U* data, \
-			decltype(data->funcTest)* = nullptr); \
-		template<typename> static no& check(...); \
-		static const bool value = sizeof(check<HAS_FUNC_T>(nullptr)) == sizeof(yes); \
-	}
-#endif
+Inspired by <http://stackoverflow.com/a/8752988>.
+Note that checkRet & check could be merged into 1 function, but VS 11 doesn't like having a
+decltype inside that enable_if; so the 2 checks are separate. */
+#define HAS_FUNC(name, funcRet, funcTest) \
+	template<typename HAS_FUNC_T> struct name { \
+		typedef char yes[1]; \
+		typedef char no[2]; \
+		template<typename HAS_FUNC_V> static void checkRet( \
+			typename std::enable_if<std::is_same<funcRet, HAS_FUNC_V>::value>::type*); \
+		template<typename HAS_FUNC_U> static yes& check( \
+			decltype(checkRet<decltype(std::declval<HAS_FUNC_U>().funcTest)>(nullptr))*); \
+		template<typename> static no& check(...); \
+		static const bool value = sizeof(check<HAS_FUNC_T>(nullptr)) == sizeof(yes); \
+	}
 
 class Util
 {

=== modified file 'test/testsfinae.cpp'
--- test/testsfinae.cpp	2012-11-10 15:40:59 +0000
+++ test/testsfinae.cpp	2012-11-23 19:35:18 +0000
@@ -6,11 +6,16 @@
 
 using namespace dcpp;
 
-struct Funcs {
+struct Base {
+	void fbase1() { }
+};
+
+struct Funcs : Base {
 	void f1() { }
 	void f2(int) { }
 	int f3() { return 0; }
 	void f4(const string&) { }
+	void f5(string&) { }
 };
 
 template<typename T>
@@ -20,6 +25,8 @@
 	HAS_FUNC(F2, void, f2(0));
 	HAS_FUNC(F3, int, f3());
 	HAS_FUNC(F4, void, f4(string()));
+	HAS_FUNC(F5, void, f5(std::function<string&()>()()));
+	HAS_FUNC(F6, void, fbase1());
 
 	// these should be false.
 	HAS_FUNC(FN1, void, lol());
@@ -30,6 +37,8 @@
 	bool test_F2() { return F2<T>::value; }
 	bool test_F3() { return F3<T>::value; }
 	bool test_F4() { return F4<T>::value; }
+	bool test_F5() { return F5<T>::value; }
+	bool test_F6() { return F6<T>::value; }
 
 	bool test_FN1() { return FN1<T>::value; }
 	bool test_FN2() { return FN2<T>::value; }
@@ -51,14 +60,12 @@
 	ASSERT_EQ(true, x.test_F2());
 	ASSERT_EQ(true, x.test_F3());
 	ASSERT_EQ(true, x.test_F4());
+	ASSERT_EQ(true, x.test_F5());
+	ASSERT_EQ(true, x.test_F6());
 
 	ASSERT_EQ(false, x.test_FN1());
-#ifndef _MSC_VER
-	/* TODO these tests ensure that the return value of the tested function is correctly validated.
-	doesn't work in MSVC, as explained by the definition of HAS_FUNC. */
 	ASSERT_EQ(false, x.test_FN2());
 	ASSERT_EQ(false, x.test_FN3());
-#endif
 
 	ASSERT_EQ(true, x.i());
 }