Adding helpful requires macros to the enable_if utility
These following set of macros, I have found very useful in C++: #define BOOST_ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE(...) __VA_ARGS__>::type #define BOOST_FUNCTION_REQUIRES(...) typename boost::enable_if_c<(__VA_ARGS__), BOOST_ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE #define BOOST_CLASS_REQUIRES(...) typename boost::enable_if_c<(__VA_ARGS__)>::type #define BOOST_REQUIRES(...) typename boost::enable_if_c<(__VA_ARGS__), int>::type = 0 Which I use like the following For functions: template <class T> BOOST_FUNCTION_REQUIRES(boost::is_arithmetic<T>::value) (T) foo(T t) { return t; } And C++11 functions: template <class T, BOOST_REQUIRES(boost::is_arithmetic<T>())> T foo(T t) { return t; } Class specializations: template <class T, class Enable = void> class A { ... }; template <class T> class A<T, BOOST_CLASS_REQUIRES(is_integral<T>())> { ... }; template <class T> class A<T, BOOST_CLASS_REQUIRES(is_float<T>())> { ... }; It would be nice if these were the added with the enable_if utility with boost. Thanks, Paul
On Friday 27 June 2014 09:10:33 paul Fultz wrote:
These following set of macros, I have found very useful in C++:
#define BOOST_ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE(...) __VA_ARGS__>::type #define BOOST_FUNCTION_REQUIRES(...) typename boost::enable_if_c<(__VA_ARGS__), BOOST_ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE
#define BOOST_CLASS_REQUIRES(...) typename boost::enable_if_c<(__VA_ARGS__)>::type
#define BOOST_REQUIRES(...) typename boost::enable_if_c<(__VA_ARGS__), int>::type = 0
Which I use like the following
For functions:
template <class T> BOOST_FUNCTION_REQUIRES(boost::is_arithmetic<T>::value) (T) foo(T t) { return t; }
And C++11 functions:
template <class T, BOOST_REQUIRES(boost::is_arithmetic<T>())> T foo(T t) { return t; }
Class specializations:
template <class T, class Enable = void> class A { ... };
template <class T> class A<T, BOOST_CLASS_REQUIRES(is_integral<T>())> { ... };
template <class T> class A<T, BOOST_CLASS_REQUIRES(is_float<T>())> { ... };
It would be nice if these were the added with the enable_if utility with boost.
Frankly, I'd prefer using enable_if directly instead of macros.
On Fri, 27 Jun 2014 09:35:14 -0700, Andrey Semashev <andrey.semashev@gmail.com> wrote:
On Friday 27 June 2014 09:10:33 paul Fultz wrote:
These following set of macros, I have found very useful in C++:
#define BOOST_ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE(...) __VA_ARGS__>::type #define BOOST_FUNCTION_REQUIRES(...) typename boost::enable_if_c<(__VA_ARGS__), BOOST_ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE
#define BOOST_CLASS_REQUIRES(...) typename boost::enable_if_c<(__VA_ARGS__)>::type
#define BOOST_REQUIRES(...) typename boost::enable_if_c<(__VA_ARGS__), int>::type = 0
Which I use like the following
For functions:
template <class T> BOOST_FUNCTION_REQUIRES(boost::is_arithmetic<T>::value) (T) foo(T t) { return t; }
And C++11 functions:
template <class T, BOOST_REQUIRES(boost::is_arithmetic<T>())> T foo(T t) { return t; }
Class specializations:
template <class T, class Enable = void> class A { ... };
template <class T> class A<T, BOOST_CLASS_REQUIRES(is_integral<T>())> { ... };
template <class T> class A<T, BOOST_CLASS_REQUIRES(is_float<T>())> { ... };
It would be nice if these were the added with the enable_if utility with boost.
Frankly, I'd prefer using enable_if directly instead of macros.
-1. I find the use of macros to be far more readable than the direct use of templates. In fact, I was earlier toying with the idea of writing such macros myself. Needless to say that I would find them to be very helpful. Paul, can the concept be extended to a DSEL-like utility? Something along the lines of: template <class T> BOOST_FUNCTION_REQUIRES(is_foo(T) and is_bar(T)) (T) foo(T t) { return t; } where "is_foo", "and", and "is_bar" are PPMP keywords. "Non-standard" conditions can be introduced via the "explicit" keyword, like: template <class T> BOOST_FUNCTION_REQUIRES(is_foo(T) and is_bar(T) or explicit(is_baz<T>::value)) (T) foo(T t) { return t; } , or clients can be given a mechanism to hook in their own keywords. (I have a mental sketch of how the latter could work, nothing implemented or tested.) Just thinking out loud ...
I find the use of macros to be far more readable than the direct use of templates. In fact, I was earlier toying with the idea of writing such macros myself. Needless to say that I would find them to be very helpful.
Besides readability, they actually help avoid the most vexing parse in C++(something template aliases can't fix).
Paul, can the concept be extended to a DSEL-like utility?
Well you can already write something like this on compilers that support `constexpr`: template <class T> BOOST_FUNCTION_REQUIRES(is_foo<T>() and is_bar<T>()) (T) foo(T t) { return t; } This could be made to work on older compilers by using expression templates, but then using literals such as `is_foo<T>::value` would fail. Perhaps a second macro like `BOOST_FUNCTION_REQUIRES_E` could be written to help avoid the confusion. Plus, having separate `_E` macros can actually still be useful in C++11 because of limitations of `constexpr`. For example, say we use a `trait` function that deduces the type parameters from a variable: template<template<class...> class Trait, class... Ts> constexpr auto trait(Ts&&... xs) { return Trait(std::forward<Ts>(xs)...); } template <class T> T foo(T t, BOOST_REQUIRES_E(trait<is_foo>(t) and trait<is_bar>(t))) { return t; } This is because `trait<is_foo>(t)` won't be a `constexpr` if `t` isn't a literal type. -- View this message in context: http://boost.2283326.n4.nabble.com/Adding-helpful-requires-macros-to-the-ena... Sent from the Boost - Dev mailing list archive at Nabble.com.
participants (4)
-
Andrey Semashev
-
Mostafa
-
paul Fultz
-
pfultz2