[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [lmi] enable_if boost to std rosetta stone
From: |
Greg Chicares |
Subject: |
Re: [lmi] enable_if boost to std rosetta stone |
Date: |
Mon, 23 Jan 2017 18:24:31 +0000 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Icedove/45.6.0 |
On 2017-01-23 01:56, Vadim Zeitlin wrote:
> On Sun, 22 Jan 2017 20:46:47 +0000 Greg Chicares <address@hidden> wrote:
>
> GC> Can't we get rid of both "::value" (as boost::enable_if does) and
> GC> "::type" (as C++14 std::enable_if_t does) at the same time?
>
> I don't see why not... At least my first naïve attempt to do it seems to
> have compiled just fine:
[...]
> I am not sure how to test this, but it looks like this ought to do the
> right thing, am I missing something?
That does seem to work (see unit test below). You'll need a separate
disable_if_t because adding '!' after the first '<' here:
detail::enable_if_t<std::is_enum<T>>* = nullptr
won't find any "::value" to negate; but some would see that as an
advantage because boost's enable-disable pair is easier to read.
Here's a unit test provided as a patch to lmi's sandbox. To use it
(drop the ".exe" of course for *nix):
$make unit_tests unit_test_targets=sandbox_test.exe
---------8<--------8<--------8<--------8<--------8<--------8<--------8<-------
diff --git a/sandbox_test.cpp b/sandbox_test.cpp
index 401b86d..1fc3ef1 100644
--- a/sandbox_test.cpp
+++ b/sandbox_test.cpp
@@ -23,8 +23,78 @@
#include "test_tools.hpp"
+#include <type_traits>
+
+// Original pair, adapted from 'xml_serializable.tpp'.
+// - switched template arg order to allow deduction
+// - the second ("disable_if") one doesn't throw (easier to test)
+
+template<typename Y, typename X>
+inline Y sfinae_cast
+ (X const& x
+ ,typename std::enable_if<std::is_same<X,Y>::value>::type* = nullptr
+ )
+{
+ return x;
+}
+
+template<typename Y, typename X>
+inline Y sfinae_cast
+ (X const&
+ ,typename std::enable_if<!std::is_same<X,Y>::value>::type* = nullptr
+ )
+{
+// Don't throw for this test:
+// fatal_error() << "Impermissible type conversion." << LMI_FLUSH;
+ return Y();
+}
+
+// Same, but using a terser idiom:
+
+namespace xyzzy
+{
+// Renamed with s/if/iff/ to avoid conflict with C++14.
+ template<typename IsTrue, typename T = void>
+ using enable_iff_t = typename std::enable_if<IsTrue::value,T>::type;
+
+ template<typename IsTrue, typename T = void>
+ using disable_iff_t = typename std::enable_if<!IsTrue::value,T>::type;
+} // namespace xyzzy
+
+template<typename Y, typename X>
+inline Y sfinae_cast_2
+ (X const& x
+ ,typename xyzzy::enable_iff_t<std::is_same<X,Y>>* = nullptr
+ )
+{
+ return x;
+}
+
+template<typename Y, typename X>
+inline Y sfinae_cast_2
+ (X const&
+// ,typename xyzzy::enable_iff_t<!std::is_same<X,Y> >* = nullptr
+// error: template argument 1 is invalid ^
+// i.e., "::type" was elided and cannot be negated here
+// so a distinct "disable" version is needed:
+ ,typename xyzzy::disable_iff_t<std::is_same<X,Y> >* = nullptr
+ )
+{
+ return Y();
+}
+
int test_main(int, char*[])
{
+ BOOST_TEST((4.0 == sfinae_cast<double >(4.0)));
+ BOOST_TEST((0U == sfinae_cast<double const>(4.0)));
+ BOOST_TEST((0L == sfinae_cast<float >(4.0)));
+ BOOST_TEST((nullptr == sfinae_cast<double* >(4.0)));
+
+ BOOST_TEST((4.0 == sfinae_cast_2<double >(4.0)));
+ BOOST_TEST((0U == sfinae_cast_2<double const>(4.0)));
+ BOOST_TEST((0L == sfinae_cast_2<float >(4.0)));
+ BOOST_TEST((nullptr == sfinae_cast_2<double* >(4.0)));
+
return 0;
}
--------->8-------->8-------->8-------->8-------->8-------->8-------->8-------
Now I wonder about two things. First, given that the Committee added
std::enable_if_t to C++14 to provide a less verbose idiom, why didn't
they go all the way and do what you've done?
Second, if I remove the code that you suggested and I mangled above
from its namespace, bringing it into the global namespace, it no longer
works. Is this some obvious mechanical error on my part, or am I missing
some subtlety? I'll present this as a full patch to HEAD rather than a
patch-upon-a-patch because I think that'll be clearer:
---------8<--------8<--------8<--------8<--------8<--------8<--------8<-------
diff --git a/sandbox_test.cpp b/sandbox_test.cpp
index 401b86d..cbfe761 100644
--- a/sandbox_test.cpp
+++ b/sandbox_test.cpp
@@ -23,8 +23,75 @@
#include "test_tools.hpp"
+#include <type_traits>
+
+// Original pair, adapted from 'xml_serializable.tpp'.
+// - switched template arg order to allow deduction
+// - the second ("disable_if") one doesn't throw (easier to test)
+
+template<typename Y, typename X>
+inline Y sfinae_cast
+ (X const& x
+ ,typename std::enable_if<std::is_same<X,Y>::value>::type* = nullptr
+ )
+{
+ return x;
+}
+
+template<typename Y, typename X>
+inline Y sfinae_cast
+ (X const&
+ ,typename std::enable_if<!std::is_same<X,Y>::value>::type* = nullptr
+ )
+{
+// Don't throw for this test:
+// fatal_error() << "Impermissible type conversion." << LMI_FLUSH;
+ return Y();
+}
+
+// Same, but using a terser idiom:
+
+// Renamed with s/if/iff/ to avoid conflict with C++14.
+ template<typename IsTrue, typename T = void>
+ using enable_iff_t = typename std::enable_if<IsTrue::value,T>::type;
+
+ template<typename IsTrue, typename T = void>
+ using disable_iff_t = typename std::enable_if<!IsTrue::value,T>::type;
+
+template<typename Y, typename X>
+inline Y sfinae_cast_2
+ (X const& x
+ ,typename enable_iff_t<std::is_same<X,Y>>* = nullptr
+ )
+{
+ return x;
+}
+
+template<typename Y, typename X>
+inline Y sfinae_cast_2
+ (X const&
+// ,typename enable_iff_t<!std::is_same<X,Y> >* = nullptr
+// error: template argument 1 is invalid ^
+// i.e., "::type" was elided and cannot be negated here
+// so a distinct "disable" version is needed:
+ ,typename disable_iff_t<std::is_same<X,Y> >* = nullptr
+ )
+{
+ return Y();
+}
+
int test_main(int, char*[])
{
+ BOOST_TEST((4.0 == sfinae_cast<double >(4.0)));
+ BOOST_TEST((0U == sfinae_cast<double const>(4.0)));
+ BOOST_TEST((0L == sfinae_cast<float >(4.0)));
+ BOOST_TEST((nullptr == sfinae_cast<double* >(4.0)));
+
+ BOOST_TEST((4.0 == sfinae_cast_2<double >(4.0)));
+ BOOST_TEST((0U == sfinae_cast_2<double const>(4.0)));
+ BOOST_TEST((0L == sfinae_cast_2<float >(4.0)));
+ BOOST_TEST((nullptr == sfinae_cast_2<double* >(4.0)));
+
return 0;
}
--------->8-------->8-------->8-------->8-------->8-------->8-------->8-------