Telegram 源码解读点滴记录
1.test_callable_plain,作用:判断参数是否与函数声明一致
using false_t = char;
struct true_t {
false_t data[2];
};
static_assert(sizeof(false_t) != sizeof(true_t), "I can't work :(");
//----------------------------is_callable_plain_v-------------------------------------
template <
typename Method,
typename ...Args,
typename = decltype(std::declval<Method>()(
std::declval<Args>()...))>
true_t test_callable_plain(Method &&, Args &&...) noexcept;
false_t test_callable_plain(...) noexcept;
template <typename Method, typename ...Args>
struct is_callable_plain
: std::bool_constant<(
sizeof(test_callable_plain(
std::declval<Method>(),
std::declval<Args>()...
)) == sizeof(true_t))> {
};
template <typename Method, typename ...Args>
constexpr bool is_callable_plain_v = is_callable_plain<Method, Args...>::value;
//--------------------------------is_callable_tuple_v--------------------------------------
template <typename Arg>
const Arg& const_ref_val() noexcept ;
template <
typename Method,
typename ...Types,
typename = decltype(std::declval<Method>()(
std::declval<Types>()...))>
true_t test_callable_tuple(
Method&&,
std::tuple<Types...>&&) noexcept;
template <
typename Method,
typename ...Types,
typename = decltype(std::declval<Method>()(
const_ref_val<Types>()...))>
true_t test_callable_tuple(
Method&&,
const std::tuple<Types...>&) noexcept;
false_t test_callable_tuple(...) noexcept;
template <typename Method, typename Arg>
constexpr bool is_callable_tuple_v = (sizeof(test_callable_tuple(
std::declval<Method>(),
std::declval<Arg>())) == sizeof(true_t));
//----------------------------------------综合两都判断---------------------------
template <typename Method, typename ...Args>
struct is_callable;
template <typename Method>
struct is_callable<Method>
: std::bool_constant<
is_callable_plain_v<Method>> {
};
template <typename Method, typename Arg>
struct is_callable<Method, Arg>
: std::bool_constant<
is_callable_plain_v<Method, Arg> ||
is_callable_tuple_v<Method, Arg> ||
is_callable_plain_v<Method>> {
};
template <typename Method, typename ...Args>
constexpr bool is_callable_v = is_callable<Method, Args...>::value;
template <typename Method, typename Arg>
inline decltype(auto) callable_invoke(Method &&method, Arg &&arg) {
if constexpr (is_callable_plain_v<Method, Arg>) {
return std::forward<Method>(method)(std::forward<Arg>(arg));
} else if constexpr (is_callable_tuple_v<Method, Arg>) {
return std::apply(
std::forward<Method>(method),
std::forward<Arg>(arg));
} else if constexpr (is_callable_v<Method>) {
return std::forward<Method>(method)();
} else {
static_assert(false_(method, arg), "Bad callable_invoke() call.");
}
}
//使用示例代码
void FnC(int age, string name) {
}
void FnTuple(int a,int b) {
}
int main()
{
auto c1 = test_callable_plain(FnC, 1); //c1值为false_t
auto c2 = test_callable_plain(FnC, 1,"FFF"); //c2值为true_t
constexpr auto c3 = is_callable_plain_v<decltype(FnC), int>; //false
constexpr auto c4 = is_callable_plain_v<decltype(FnC), int,string>;//true
const std::tuple<int,int> t1 = std::make_tuple(1, 1);
auto f = test_callable_tuple(FnTuple,t1); //true_t
const std::tuple<int, string> t2 = std::make_tuple(1, "FF");
auto f2 = test_callable_tuple(FnTuple, t2); //false_t
}