Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++17 check for valid expression

Tags:

c++

c++17

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.

like image 646
chila Avatar asked Oct 17 '22 11:10

chila


1 Answers

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

like image 184
Vittorio Romeo Avatar answered Oct 30 '22 00:10

Vittorio Romeo