Basing my code on this and this, I've written this version:
#include <iostream>
#include <boost/preprocessor.hpp>
#include <boost/callable_traits/is_invocable.hpp>
#define IS_VALID_EXPANDER_BEGIN(count) \
[](BOOST_PP_REPEAT(count, IS_VALID_EXPANDER_MIDDLE, \
_)) constexpr->decltype IS_VALID_EXPANDER_END
#define IS_VALID_EXPANDER_MIDDLE(z, idx, _) BOOST_PP_COMMA_IF(idx) auto _##idx
#define IS_VALID_EXPANDER_END(...) \
(__VA_ARGS__){})
#define IS_VALID(...) \
is_valid<__VA_ARGS__>(IS_VALID_EXPANDER_BEGIN( \
BOOST_PP_VARIADIC_SIZE(__VA_ARGS__))
template <typename... Ts, typename TF>
static constexpr auto is_valid(TF)
{
return boost::callable_traits::is_invocable<std::decay_t<TF>(Ts...), Ts...>{};
}
struct Test {};
int main()
{
std::cout << IS_VALID(std::ostream&, double)(_0 << _1) << std::endl;
std::cout << IS_VALID(std::ostream&, Test)(_0 << _1) << std::endl;
}
However, the results are:
1
1
I can't figure out why.
Your lambda is taking arguments by value, which doesn't allow you to test std::ostream& << T
. Change your macro to:
#define IS_VALID_EXPANDER_BEGIN(count) \
[](BOOST_PP_REPEAT(count, IS_VALID_EXPANDER_MIDDLE, \
&&_)) constexpr->decltype IS_VALID_EXPANDER_END
Also, your use of is_invocable
is wrong - it should be:
template <typename... Ts, typename TF>
static constexpr auto is_valid(TF)
{
return boost::callable_traits::is_invocable<std::decay_t<TF>, Ts...>{};
}
(You should use std::is_invocable
anyway, it is available in C++17.)
live example on wandbox.org
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With