Hi, This is the second time that I have found the following function useful when playing with variants of Optional library: template <typename T, typename U> typename std::enable_if<std::is_convertible<U, T>::value, T>::type convert(U && u) { return std::forward<U>(u); } It performs an implicit conversion from U to T, but you can call it explicitly. [1st] time I needed it to implement the behavior of value_or (described in http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3672.html#optional.... ): template <class U> constexpr T optional<T>::value_or(U&& v) const&; Requires: is_copy_constructible<T>::value is true and is_convertible<U&&, T>::value is true. Returns: bool(*this) ? **this : static_cast<T>(std::forward<U>(v)). This needs to be implemented in one expression in C++11, because the function is constexpr, so in the ternary operator, I could either apply no cast and risk unnecessary ambiguity in result type in certain cases, or use a static_cast and bring the explicit conversions in that I didn't want. Function convert() saved the day. [2nd] time was when trying to disable the overload in C++11 using SFINAE, but I didn't want to use enable_if (see a more complete example here: http://akrzemi1.wordpress.com/examples/overloading-enable_if-3/): template <typename U> auto value_or(U const& v) const -> decltype(convert<T>(v)) { if (*this) return this->value(); else return v; } template <typename F> auto value_or(F const& f) const -> decltype(convert<T>(f())) { if (*this) return this->value(); else return f(); } I wanted to check with Boost developers if you find such function convert generally useful (and worth adding somewhere in Boost), or is it just my specific needs. Regards, &rzej
On Sun, Jun 29, 2014 at 12:58 AM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote:
Hi, This is the second time that I have found the following function useful when playing with variants of Optional library:
template <typename T, typename U> typename std::enable_if<std::is_convertible<U, T>::value, T>::type convert(U && u) { return std::forward<U>(u); }
It performs an implicit conversion from U to T, but you can call it explicitly.
Isn't it what implicit_cast does? See boost/implicit_cast.hpp.
Le 28/06/14 23:34, Andrey Semashev a écrit :
On Sun, Jun 29, 2014 at 12:58 AM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote:
Hi, This is the second time that I have found the following function useful when playing with variants of Optional library:
template <typename T, typename U> typename std::enable_if<std::is_convertible<U, T>::value, T>::type convert(U && u) { return std::forward<U>(u); }
It performs an implicit conversion from U to T, but you can call it explicitly. Isn't it what implicit_cast does? See boost/implicit_cast.hpp.
Andrey, is implicit_cast SFINAE friendly? Vicente
On Sunday 29 June 2014 10:15:00 Vicente J. Botet Escriba wrote:
Le 28/06/14 23:34, Andrey Semashev a écrit :
On Sun, Jun 29, 2014 at 12:58 AM, Andrzej Krzemienski
<akrzemi1@gmail.com> wrote:
Hi, This is the second time that I have found the following function useful when playing with variants of Optional library:
template <typename T, typename U> typename std::enable_if<std::is_convertible<U, T>::value, T>::type convert(U && u) { return std::forward<U>(u); }
It performs an implicit conversion from U to T, but you can call it explicitly.
Isn't it what implicit_cast does? See boost/implicit_cast.hpp.
Andrey, is implicit_cast SFINAE friendly?
I'm not sure, but I think so. It doesn't seem callable if U is not convertible.
2014-06-29 10:15 GMT+02:00 Vicente J. Botet Escriba < vicente.botet@wanadoo.fr>:
Le 28/06/14 23:34, Andrey Semashev a écrit :
On Sun, Jun 29, 2014 at 12:58 AM, Andrzej Krzemienski
<akrzemi1@gmail.com> wrote:
Hi, This is the second time that I have found the following function useful when playing with variants of Optional library:
template <typename T, typename U> typename std::enable_if<std::is_convertible<U, T>::value, T>::type convert(U && u) { return std::forward<U>(u); }
It performs an implicit conversion from U to T, but you can call it explicitly.
Isn't it what implicit_cast does? See boost/implicit_cast.hpp.
Andrey, is implicit_cast SFINAE friendly?
I haven't check it, but it looks like it is. The conversion is performed outside the function so it should work with decltype(expression) trick. It looks better to my implementation as it does not require enable_if or forward. But it looks implicit_cast prevents copy elision (you cannot elide from function parameter), so it incurs the cost of one move construction. Regards, &rzej
2014-06-28 22:58 GMT+02:00 Andrzej Krzemienski <akrzemi1@gmail.com>:
Hi, This is the second time that I have found the following function useful when playing with variants of Optional library:
template <typename T, typename U> typename std::enable_if<std::is_convertible<U, T>::value, T>::type convert(U && u) { return std::forward<U>(u); }
It performs an implicit conversion from U to T, but you can call it explicitly.
+1 I even have such a function in my tools, and use it often. I chose a shorter name "as", because since this only forces an implicit conversion, I find verbosity unwanted here. Consider preventing dangerous uses like this (not tested): auto& x = convert<T const&>( U() ); You can prevent that by adding a static_assert in this function: // Prevent returning an lvalue reference to a temporary BOOST_STATIC_ASSERT( !is_lvalue_reference<T>::value || is_reference<U>::value ); BTW, why not get rid of the enable_if< is_convertible > part? Won't a message "U isn't convertible to T" pointing into the function be more readable, than a message "There's no 'convert' function"? Regards, Kris PS. Look, how nice this looks (it even sounds English): cout << boost::as<double>(2) / 3 << endl; Compared to: cout << boost::convert<double>(2) / 3 << endl; Not to mention: cout << static_cast<double>(2) / 3 << endl; which (like Andrzej explained) brings in potentially unwanted explicit conversions.
2014-06-28 23:52 GMT+02:00 Krzysztof Czainski <1czajnik@gmail.com>:
2014-06-28 22:58 GMT+02:00 Andrzej Krzemienski <akrzemi1@gmail.com>:
Hi, This is the second time that I have found the following function useful when playing with variants of Optional library:
template <typename T, typename U> typename std::enable_if<std::is_convertible<U, T>::value, T>::type convert(U && u) { return std::forward<U>(u); }
It performs an implicit conversion from U to T, but you can call it explicitly.
+1
I even have such a function in my tools, and use it often.
I chose a shorter name "as", because since this only forces an implicit conversion, I find verbosity unwanted here.
Consider preventing dangerous uses like this (not tested): auto& x = convert<T const&>( U() );
You can prevent that by adding a static_assert in this function: // Prevent returning an lvalue reference to a temporary BOOST_STATIC_ASSERT( !is_lvalue_reference<T>::value || is_reference<U>::value );
BTW, why not get rid of the enable_if< is_convertible > part? Won't a message "U isn't convertible to T" pointing into the function be more readable, than a message "There's no 'convert' function"?
If I remove enable_if, my second use cans will stop working -- because the semantics of convert() are no longer visible to sfinae. Regards, &rzej
participants (4)
-
Andrey Semashev
-
Andrzej Krzemienski
-
Krzysztof Czainski
-
Vicente J. Botet Escriba