我目前有一个系统将@$sayfa=$_GET['s'];
$kacar=12;
$toplansayfa=ceil(mysql_num_rows($cat)/$kacar);
$baslangic=($sayfa * $kacar) - $kacar;
$bul_cat=mysql_query("
Select m.Image_link AS link
, m.Name
, m.ID
, c.Name AS catName
from movie m
join has_category Mc
on m.ID = mc.movie_id
join category c
on c.ID = mc.category_id
where c.Name = '$category'
ORDER
BY ID desc
limit $baslangic, $kacar
");
echo mysql_error();->
“连接”到函数中。这个signal
是一个可变参数模板,它具有作为模板参数的signal
函数的参数。
在当前的实现中,我显然无法连接到参数不完全相同的函数(或那些可以转换为的函数)作为connect
的参数。现在,当我试图模仿Qt的signal
/ signal
/ slot
时,我还希望将connect
个signal
参数连接到N
slot
个M<N
个参数,它们是完全明确定义的(即忽略信号的>M
参数并将第一个M传递给连接函数)。有关我最简单形式的代码示例,请参阅Coliru。
所以问题是双重的:
connect
调用适用于函数void g(int);
?emit
调用适用于函数void g(int);
?我猜我必须为slot
及其调用函数制作一些“魔法”参数包减速器,但是我看不出它们应该如何组合在一起因此很难实际上开始尝试编写解决方案。如果至少Clang / GCC和Visual Studio 2015可以编译它,我可以使用仅限C ++ 17的解决方案。
上面链接的代码是为了完整性:
#include <memory>
#include <vector>
template<typename... ArgTypes>
struct slot
{
virtual ~slot() = default;
virtual void call(ArgTypes...) const = 0;
};
template<typename Callable, typename... ArgTypes>
struct callable_slot : slot<ArgTypes...>
{
callable_slot(Callable callable) : callable(callable) {}
void call(ArgTypes... args) const override { callable(args...); }
Callable callable;
};
template<typename... ArgTypes>
struct signal
{
template<typename Callable>
void connect(Callable callable)
{
slots.emplace_back(std::make_unique<callable_slot<Callable, ArgTypes...>>(callable));
}
void emit(ArgTypes... args)
{
for(const auto& slot : slots)
{
slot->call(args...);
}
}
std::vector<std::unique_ptr<slot<ArgTypes...>>> slots;
};
void f(int, char) {}
int main()
{
signal<int, char> s;
s.connect(&f);
s.emit(42, 'c');
}
答案 0 :(得分:3)
template<class...> struct voider { using type = void; };
template<class... Ts> using voidify = typename voider<Ts...>::type;
template<class C, class...Args>
using const_lvalue_call_t = decltype(std::declval<const C&>()(std::declval<Args>()...));
template<class T, std::size_t...Is>
auto pick_from_tuple_impl(T &&, std::index_sequence<Is...>)
-> std::tuple<std::tuple_element_t<Is, T>...>;
template<class Tuple, class = std::enable_if_t<(std::tuple_size<Tuple>::value > 0)>>
using drop_last = decltype(pick_from_tuple_impl(std::declval<Tuple>(),
std::make_index_sequence<std::tuple_size<Tuple>::value - 1>()));
template<class C, class ArgsTuple, class = void>
struct try_call
: try_call<C, drop_last<ArgsTuple>> {};
template<class C, class...Args>
struct try_call<C, std::tuple<Args...>, voidify<const_lvalue_call_t<C, Args...>>> {
template<class... Ts>
static void call(const C& c, Args&&... args, Ts&&... /* ignored */) {
c(std::forward<Args>(args)...);
}
};
然后在callable_slot
:
void call(ArgTypes... args) const override {
using caller = try_call<Callable, std::tuple<ArgTypes...>>;
caller::call(callable, std::forward<ArgTypes>(args)...);
}
对于成员指针支持(这需要SFINAE友好std::result_of
),请将const_lvalue_call_t
更改为
template<class C, class...Args>
using const_lvalue_call_t = std::result_of_t<const C&(Args&&...)>;
然后将try_call::call
中的实际通话更改为
std::ref(c)(std::forward<Args>(args)...);
对于左值犊牛来说,这是穷人的std::invoke
。如果您有C ++ 17,请直接使用std::invoke
(并使用std::void_t
代替voidify
,但我喜欢后者的声音。
答案 1 :(得分:1)
不确定理解你到底想要什么......但是...... std::tuple
和std::make_index_sequence
......
首先,您需要一个类型特征,它可以为您提供函数的参数数量(或std::function
)
template <typename>
struct numArgs;
template <typename R, typename ... Args>
struct numArgs<R(*)(Args...)>
: std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <typename R, typename ... Args>
struct numArgs<std::function<R(Args...)>>
: std::integral_constant<std::size_t, sizeof...(Args)>
{ };
接下来,您必须在constexpr
中添加callable_slot
值,以记住Callable
函数中的参数数量
static constexpr std::size_t numA { numArgs<Callable>::value };
然后你必须修改call()
方法以在std::tuple<ArgTypes...>
中打包参数并调用另一个传递元组的方法和从0到numA
的索引序列
void call(ArgTypes... args) const override
{ callI(std::make_tuple(args...), std::make_index_sequence<numA>{}); }
最后,您必须在CallI()
中调用仅包含参数元组的第一个callable()
元素的numA
函数
template <std::size_t ... Is>
void callI (std::tuple<ArgTypes...> const & t,
std::index_sequence<Is...> const &) const
{ callable(std::get<Is>(t)...); }
以下是一个完整的工作示例
#include <memory>
#include <vector>
#include <iostream>
#include <functional>
template <typename>
struct numArgs;
template <typename R, typename ... Args>
struct numArgs<R(*)(Args...)>
: std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <typename R, typename ... Args>
struct numArgs<std::function<R(Args...)>>
: std::integral_constant<std::size_t, sizeof...(Args)>
{ };
template <typename ... ArgTypes>
struct slot
{
virtual ~slot() = default;
virtual void call(ArgTypes...) const = 0;
};
template <typename Callable, typename ... ArgTypes>
struct callable_slot : slot<ArgTypes...>
{
static constexpr std::size_t numA { numArgs<Callable>::value };
callable_slot(Callable callable) : callable(callable)
{ }
template <std::size_t ... Is>
void callI (std::tuple<ArgTypes...> const & t,
std::index_sequence<Is...> const &) const
{ callable(std::get<Is>(t)...); }
void call(ArgTypes... args) const override
{ callI(std::make_tuple(args...), std::make_index_sequence<numA>{}); }
Callable callable;
};
template <typename ... ArgTypes>
struct signal
{
template <typename Callable>
void connect(Callable callable)
{
slots.emplace_back(
std::make_unique<callable_slot<Callable, ArgTypes...>>(callable));
}
void emit(ArgTypes... args)
{ for(const auto& slot : slots) slot->call(args...); }
std::vector<std::unique_ptr<slot<ArgTypes...>>> slots;
};
void f (int i, char c)
{ std::cout << "--- f(" << i << ", " << c << ")" << std::endl; }
void g (int i)
{ std::cout << "--- g(" << i << ")" << std::endl; }
struct foo
{
static void j (int i, char c)
{ std::cout << "--- j(" << i << ", " << c << ")" << std::endl; }
void k (int i)
{ std::cout << "--- k(" << i << ")" << std::endl; }
};
int main ()
{
std::function<void(int, char)> h { [](int i, char c)
{ std::cout << "--- h(" << i << ", " << c << ")" << std::endl; }
};
std::function<void(int)> i { [](int i)
{ std::cout << "--- i(" << i << ")" << std::endl; }
};
using std::placeholders::_1;
foo foo_obj{};
std::function<void(int)> k { std::bind(&foo::k, foo_obj, _1) };
signal<int, char> s;
s.connect(f);
s.connect(g);
s.connect(h);
s.connect(i);
s.connect(foo::j);
s.connect(k);
s.emit(42, 'c');
}
此示例需要C ++ 14,因为使用std::make_index_sequence
和std::index_sequence
。
替换它们并准备符合C ++ 11的解决方案并不是非常困难。