C++ C++;17检查有效表达式

C++ C++;17检查有效表达式,c++,c++17,c++20,C++,C++17,C++20,基于和,我编写了以下版本: #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_MIDDL

基于和,我编写了以下版本:

#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;
}

我不明白为什么。

您的lambda按值获取参数,这不允许您测试
std::ostream&
然后修改:

template<class F>
constexpr auto invokeable( F&& f ) {
  return [](auto&&...args) {
    return std::is_invocable< F&&, untag_t<decltype(args)>... >{};
  };
}
模板
constexpr自动可调用(F&&F){
返回[](自动和…参数){
返回std::is_invocable{};
};
}
它允许传递
tag
而不是
std::ostream&
类型的左值,以测试所有
std::ostream&
是否在该插槽中工作


这里使用的唯一宏是
返回
,这使SFINAE友好的lambda变得更容易。在任何情况下,都有许多建议添加与
返回值
等价的内容。

C++17而你正在搞乱可变宏为什么?@rubenvb:这里链接文章的作者。可变宏只是为就地表达式有效性评估提供语法糖分的一种方式。如果没有宏,调用端看起来会很可怕,会损害可读性,并破坏这个构造的目的。啊,我没有注意到这段代码来自某个地方,描述了它的用法。那就别忘了我的评论!“有许多建议添加与
返回值
”相当的内容-我记得看到的唯一一件事是Barry拒绝的简洁lambda语法建议。还有什么?@vitt我想我看到了另一个,但可能是协同程序代码工作。由于某些原因,我的库没有“std::is_invocable”。您的代码不也应该有&&吗?
#define IS_VALID_EXPANDER_BEGIN(count)                    \
    [](BOOST_PP_REPEAT(count, IS_VALID_EXPANDER_MIDDLE, \
        &&_)) constexpr->decltype IS_VALID_EXPANDER_END
template <typename... Ts, typename TF>
static constexpr auto is_valid(TF)
{
    return boost::callable_traits::is_invocable<std::decay_t<TF>, Ts...>{};
}
#define RETURNS(...) \
  noexcept(noexcept(__VA_ARGS__)) \
  -> decltype(__VA_ARGS__) \
  { return __VA_ARGS__; }

template<class F>
constexpr auto invokeable( F&& f ) {
  return [](auto&&...args) {
    return std::is_invocable< F&&, decltype(args)... >{};
  };
}
std::cout << invokeable([](auto& lhs, auto&& v) RETURNS( lhs << v ))( std::cout, 0.0 ) << std::endl;
std::cout << invokeable([](auto& lhs, auto&& v) RETURNS( lhs << v ))( std::cout, Test{} ) << std::endl;
std::cout << invokeable(_0 << _1)( std::cout, Test{} ) << std::endl;
template<class T>
struct tag_t { using type=T; };
template<class T>
constexpr tag_t<T> tag{};

template<class X>
struct untag { using type=X; };
template<class X>
using untag_t = typename untag<X>::type;
template<class T>
struct untag<tag_t<T>> { using type=T; };
template<class T>
struct untag<tag_t<T>&&> { using type=T; };
template<class T>
struct untag<tag_t<T>&> { using type=T; };
template<class T>
struct untag<tag_t<T>const &> { using type=T; };
template<class F>
constexpr auto invokeable( F&& f ) {
  return [](auto&&...args) {
    return std::is_invocable< F&&, untag_t<decltype(args)>... >{};
  };
}