std::is_invocable 用于测试任意方法是否存在的语法(不仅是 operator())
std::is_invocable syntax for testing existence of an arbitrary method (not only operator())
在 C++17 中我知道我可以写:
#include <type_traits>
struct A
{
size_t operator()(double x) const { return 1; };
};
int main()
{
static_assert(std::is_invocable_r_v<size_t, A, double>);
}
但是现在我想使用std::is_invocable来测试任意方法的存在(这里是size(double)
方法):
#include <type_traits>
struct A
{
size_t size(double x) const { return 1; };
};
int main()
{
static_assert(std::is_invocable_r_v<size_t, ???, double>);
}
问题是如何填写“???”让它工作 ?
我刚刚意识到正确的语法是:
static_assert(std::is_invocable_r_v<size_t, decltype(&A::size), A, double>);
这是一个工作示例
// -*- compile-command: "g++ -std=c++17 demo.cpp -o demo"; -*-
#include <type_traits>
struct A
{
size_t operator()(double x) const { return 1; };
size_t size(double x) const { return 1; };
};
int main()
{
static_assert(std::is_invocable_r_v<size_t, A, double>);
static_assert(std::is_invocable_r_v<size_t, decltype(&A::size), A, double>);
return EXIT_SUCCESS;
}
template <typename T, typename... Args>
using call_size_t = decltype(std::declval<T>().size(std::declval<Args>()...);
template <typename R, typename T, typename... Args>
using is_size_callable = is_detected_convertible<R, call_size_t, T, Args...>;
static_assert(is_size_callable<size_t, A, double>::value);
这有利于使用重载的成员函数 size
、模板或采用默认参数。
C++20 中的概念:
template <typename T, typename R, typename... Args>
concept is_size_callable = requires (T t, Args... args) {
{ t.size(std::forward<Args>(args)...) } -> std::convertible_to<R>;
};
static_assert(is_size_callable<A, size_t, double>);
我翻转了参数以将 T
放在第一位,因为这将允许 type-constraint 语法:
template <is_size_callable<size_t, double> T>
void foo(T );
foo(A{});
#define RETURNS( ... ) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define METHOD( ... ) \
[]( auto&& self, auto&&...args ) \
RETURNS( decltype(self)(self).__VA_ARGS__( decltype(args)(args)... ) )
struct A
{
std::size_t size(double x) const { return 1; };
};
int main()
{
static_assert(std::is_invocable_r<std::size_t, decltype(METHOD(size)), A&, double>{});
}
和c++17:
#define RETURNS( ... ) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define METHOD( ... ) \
[]( auto&& self, auto&&...args ) \
RETURNS( decltype(self)(self).__VA_ARGS__( decltype(args)(args)... ) )
auto call_size = METHOD(size);
struct A
{
std::size_t size(double x) const { return 1; };
};
int main()
{
static_assert(std::is_invocable_r<std::size_t, decltype(call_size), A&, double>{});
}
(注意:我使用 ...
因为宏不知道 <,>
样式的括号和逗号)
在 C++17 中我知道我可以写:
#include <type_traits>
struct A
{
size_t operator()(double x) const { return 1; };
};
int main()
{
static_assert(std::is_invocable_r_v<size_t, A, double>);
}
但是现在我想使用std::is_invocable来测试任意方法的存在(这里是size(double)
方法):
#include <type_traits>
struct A
{
size_t size(double x) const { return 1; };
};
int main()
{
static_assert(std::is_invocable_r_v<size_t, ???, double>);
}
问题是如何填写“???”让它工作 ?
我刚刚意识到正确的语法是:
static_assert(std::is_invocable_r_v<size_t, decltype(&A::size), A, double>);
这是一个工作示例
// -*- compile-command: "g++ -std=c++17 demo.cpp -o demo"; -*-
#include <type_traits>
struct A
{
size_t operator()(double x) const { return 1; };
size_t size(double x) const { return 1; };
};
int main()
{
static_assert(std::is_invocable_r_v<size_t, A, double>);
static_assert(std::is_invocable_r_v<size_t, decltype(&A::size), A, double>);
return EXIT_SUCCESS;
}
template <typename T, typename... Args>
using call_size_t = decltype(std::declval<T>().size(std::declval<Args>()...);
template <typename R, typename T, typename... Args>
using is_size_callable = is_detected_convertible<R, call_size_t, T, Args...>;
static_assert(is_size_callable<size_t, A, double>::value);
这有利于使用重载的成员函数 size
、模板或采用默认参数。
C++20 中的概念:
template <typename T, typename R, typename... Args>
concept is_size_callable = requires (T t, Args... args) {
{ t.size(std::forward<Args>(args)...) } -> std::convertible_to<R>;
};
static_assert(is_size_callable<A, size_t, double>);
我翻转了参数以将 T
放在第一位,因为这将允许 type-constraint 语法:
template <is_size_callable<size_t, double> T>
void foo(T );
foo(A{});
#define RETURNS( ... ) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define METHOD( ... ) \
[]( auto&& self, auto&&...args ) \
RETURNS( decltype(self)(self).__VA_ARGS__( decltype(args)(args)... ) )
struct A
{
std::size_t size(double x) const { return 1; };
};
int main()
{
static_assert(std::is_invocable_r<std::size_t, decltype(METHOD(size)), A&, double>{});
}
和c++17:
#define RETURNS( ... ) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define METHOD( ... ) \
[]( auto&& self, auto&&...args ) \
RETURNS( decltype(self)(self).__VA_ARGS__( decltype(args)(args)... ) )
auto call_size = METHOD(size);
struct A
{
std::size_t size(double x) const { return 1; };
};
int main()
{
static_assert(std::is_invocable_r<std::size_t, decltype(call_size), A&, double>{});
}
(注意:我使用 ...
因为宏不知道 <,>
样式的括号和逗号)