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)>... >{};
};
}