- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在尝试为纯模板单元测试库编写一些模板函数,特别是针对 Qt。
在这个库中,我有一个可变参数模板,它接收可变数量的对象和仿函数(实际上是 Qt5 信号),它们总是彼此相邻配对,如 QObject, signal, etc...
中所示。然后最好跟着可变数量的信号参数。
// implementation.h
template <typename T, typename U, typename... Sargs, typename... Fargs>
void test_signal_daisy_chain(T* t, void(T::*t_signal)(Fargs...),
U* u, void(U::*u_signal)(Fargs...),
Sargs... sargs,
Fargs... fargs) {...}
// client.cpp
test_signal_daisy_chain(object, &Object::signal1,
object, &Object::signal2,
object, &Object::signal3,
1, 2, 3); // where the signals are defined as void(Object::*)(int, int, int)
在哪里Fargs...
对应于 t_signal
中的两个参数和 u_signal
以及传递给此函数进行测试的参数,以及 Sargs...
对应于变量 QObject
和信号成员函数 ( void(T::*)(Fargs...)
) 为了测试的明确目的而发出。
不出所料,由于“模板参数推导/替换失败”,我得到“没有匹配的函数”,我的 ClangCodeModel 插件警告我需要 6 个参数,但给出了 8 个。
// implementation.h
template <typename... Fargs>
struct wrapper
{
template <typename T, typename U, typename... Sargs>
void test_signal_daisy_chain(Fargs... fargs,
T* t, void(T::*t_signal)(Fargs...),
U* u, void(U::*u_signal)(Fargs...),
Sargs... sargs) {...}
// client.cpp
wrapper<int, int, int>::test_signal_daisy_chain(1, 2, 3,
object, &Object::signal1,
object, &Object::signal2,
object, &Object::signal3);
我不满足于必须在函数调用的开头和包装器模板类型参数中显式定义可变函数参数。事实上,我最初感到惊讶的是,不能仅仅因为它们要匹配仿函数的变量参数就可以推断出。我愿意使用包装器函数而不是包装器类,因为我已经设置了一个详细的命名空间,为了提供一个干净且用户友好的 API,我愿意弄乱它。
注意:信号参数可以是从基元到用户定义类型到 POD 结构到模板类的任何地方,所有的长度都是可变的。
编辑 1:c++11 是一项硬性要求,因此您可以在答案中保留 >c++11 功能,只要它们具有一些 c++ 11 解决方法,即 auto...
很容易修复,auto myFunction = []() constexpr {...};
更不用说了。如果使用 if constexpr
而不是递归 template <std::size_t>
helper 函数节省空间并提供更简洁、完整和面向 future 的答案,然后请选择您认为最好的标准。
最佳答案
最简单的做法是在一开始将参数打包成一个元组,并将元组传递给test_signal_daisy_chain_impl
:
template < typename... Fargs,
typename T, typename... Sargs>
void test_signal_daisy_chain_impl(const std::tuple<Fargs...> & fargs,
T* t, void(T::*t_signal)(Fargs...),
Sargs &&... sargs)
{
// apply unpacks the tuple
std::apply([&](auto ...params)
{
(t->*t_signal)(params...);
}, fargs);
// Although packed into the tuple, the elements in
// the tuple were not removed from the parameter list,
// so we have to ignore a tail of the size of Fargs.
if constexpr (sizeof...(Sargs) > sizeof...(Fargs))
test_signal_daisy_chain_impl(fargs, std::forward<Sargs>(sargs)...);
}
// Get a tuple out of the last I parameters
template <std::size_t I, typename Ret, typename T, typename... Qargs>
Ret get_last_n(T && t, Qargs && ...qargs)
{
static_assert(I <= sizeof...(Qargs) + 1,
"Not enough parameters to pass to the signal function");
if constexpr(sizeof...(Qargs)+1 == I)
return {std::forward<T>(t), std::forward<Qargs>(qargs)...};
else
return get_last_n<I, Ret>(std::forward<Qargs>(qargs)...);
}
template <typename T, typename... Fargs,
typename... Qargs>
void test_signal_daisy_chain(T* t, void(T::*t_signal)(Fargs...),
Qargs&&... qargs)
{
static_assert((sizeof...(Qargs) - sizeof...(Fargs)) % 2 == 0,
"Expecting even number of parameters for object-signal pairs");
if constexpr ((sizeof...(Qargs) - sizeof...(Fargs)) % 2 == 0) {
auto fargs = get_last_n<sizeof...(Fargs), std::tuple<Fargs...>>(
std::forward<Qargs>(qargs)...);
test_signal_daisy_chain_impl(fargs, t, t_signal,
std::forward<Qargs>(qargs)...);
}
}
以及用法:
class Object {
public:
void print_vec(const std::vector<int> & vec)
{
for (auto elem: vec) std::cout << elem << ", ";
}
void signal1(const std::vector<int> & vec)
{
std::cout << "signal1(";
print_vec(vec);
std::cout << ")\n";
}
void signal2(const std::vector<int> & vec)
{
std::cout << "signal2(";
print_vec(vec);
std::cout << ")\n";
}
void signal_int1(int a, int b)
{ std::cout << "signal_int1(" << a << ", " << b << ")\n"; }
void signal_int2(int a, int b)
{ std::cout << "signal_int2(" << a << ", " << b << ")\n"; }
void signal_int3(int a, int b)
{ std::cout << "signal_int3(" << a << ", " << b << ")\n"; }
};
int main()
{
Object object;
test_signal_daisy_chain(&object, &Object::signal1,
&object, &Object::signal2 ,
std::vector{1,2,3});
test_signal_daisy_chain(&object, &Object::signal_int1,
&object, &Object::signal_int2 ,
&object, &Object::signal_int3,
1,2);
}
由于 C++11 是硬约束,因此有一个更丑陋的解决方案,基于相同的原则。必须实现 std::apply
和 std::make_index_sequence
之类的东西。使用重载代替 if constexpr(....)
:
template <std::size_t ...I>
struct indexes
{
using type = indexes;
};
template<std::size_t N, std::size_t ...I>
struct make_indexes
{
using type_aux = typename std::conditional<
(N == sizeof...(I)),
indexes<I...>,
make_indexes<N, I..., sizeof...(I)>>::type;
using type = typename type_aux::type;
};
template <typename Tuple, typename T, typename Method, std::size_t... I>
void apply_method_impl(
Method t_signal, T* t, const Tuple& tup, indexes<I...>)
{
return (t->*t_signal)(std::get<I>(tup)...);
}
template <typename Tuple, typename T, typename Method>
void apply_method(const Tuple & tup, T* t, Method t_signal)
{
apply_method_impl(
t_signal, t, tup,
typename make_indexes<
std::tuple_size<Tuple>::value>::type{});
}
template < typename... Fargs, typename... Sargs>
typename std::enable_if<(sizeof...(Fargs) == sizeof...(Sargs)), void>::type
test_signal_daisy_chain_impl(const std::tuple<Fargs...> & ,
Sargs &&...)
{}
template < typename... Fargs,
typename T, typename... Sargs>
void test_signal_daisy_chain_impl(const std::tuple<Fargs...> & fargs,
T* t, void(T::*t_signal)(Fargs...),
Sargs &&... sargs)
{
apply_method(fargs, t, t_signal);
// Although packed into the tuple, the elements in
// the tuple were not removed from the parameter list,
// so we have to ignore a tail of the size of Fargs.
test_signal_daisy_chain_impl(fargs, std::forward<Sargs>(sargs)...);
}
// Get a tuple out of the last I parameters
template <std::size_t I, typename Ret, typename T, typename... Qargs>
typename std::enable_if<sizeof...(Qargs)+1 == I, Ret>::type
get_last_n(T && t, Qargs && ...qargs)
{
return Ret{std::forward<T>(t), std::forward<Qargs>(qargs)...};
}
template <std::size_t I, typename Ret, typename T, typename... Qargs>
typename std::enable_if<sizeof...(Qargs)+1 != I, Ret>::type
get_last_n(T && , Qargs && ...qargs)
{
static_assert(I <= sizeof...(Qargs) + 1, "Not enough parameters to pass to the singal function");
return get_last_n<I, Ret>(std::forward<Qargs>(qargs)...);
}
template <typename T, typename... Fargs,
typename... Qargs>
void test_signal_daisy_chain(T* t, void(T::*t_signal)(Fargs...),
Qargs&&... qargs)
{
static_assert((sizeof...(Qargs) - sizeof...(Fargs)) % 2 == 0,
"Expecting even number of parameters for object-signal pairs");
auto fargs = get_last_n<sizeof...(Fargs), std::tuple<Fargs...>>(
std::forward<Qargs>(qargs)...);
test_signal_daisy_chain_impl(fargs, t, t_signal,
std::forward<Qargs>(qargs)...);
}
可以通过将所有参数存储在一个元组中来避免运行时递归。以下 test_signal_daisy_chain_flat()
正是这样做的,同时保留与 test_signal_daisy_chain()
相同的接口(interface):
template <typename Fargs, typename Pairs, std::size_t ...I>
void apply_pairs(Fargs && fargs, Pairs && pairs, const indexes<I...> &)
{
int dummy[] = {
(apply_method(std::forward<Fargs>(fargs),
std::get<I*2>(pairs),
std::get<I*2+1>(pairs)),
0)...
};
(void)dummy;
}
template <typename T, typename... Fargs,
typename... Qargs>
void test_signal_daisy_chain_flat(T* t, void(T::*t_signal)(Fargs...),
Qargs&&... qargs)
{
static_assert((sizeof...(Qargs) - sizeof...(Fargs)) % 2 == 0,
"Expecting even number of parameters for object-signal pairs");
auto fargs = get_last_n<sizeof...(Fargs), std::tuple<Fargs...>>(
std::forward<Qargs>(qargs)...);
std::tuple<T*, void(T::*)(Fargs...), const Qargs&...> pairs{
t, t_signal, qargs...};
apply_pairs(fargs, pairs,
typename make_indexes<(sizeof...(Qargs) - sizeof...(Fargs))/2>
::type{});
}
注意事项:
关于c++ - 推导多个参数包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52168394/
通过终端,您可以使用命令 - “SetFile -a B 文件名” 以编程方式,我认为我应该通过[[NSFileManager defaultManager] createDirectoryAtPat
嗨,正在尝试书中的一些示例:Practical Graph mining with R对于子图挖掘: library(subgraphMining) library(igraph) graph1 =
代码中的相同问题: class Foo { int getIntProperty () { ... } CustomObject getObjectProperty () { ... }
所以这可能是一个愚蠢的问题,但它已经困扰我一段时间了。 使用 React,我创建了两个组件(Buttons.js 和 Message.js),每个组件都有一个导出。但是,现在我希望将这两个组件用作 n
从今天早上开始,我发现我无法再从某个范围安装任何 NPM 包(或任何具有依赖项的包)。例如,如果我输入 npm i webpack 我会收到以下错误... npm ERR! code E401 npm
我在这里搜索过,Angular 2, @ngtools/webpack, AOT ,但对我不起作用。我运行了 npm install 命令。我正在做的是创建一个新的 Angular 2 项目。当我运行
情况: 我有一个 Swift 包,将其命名为 lib。 lib 位于其自己的存储库中。在lib的仓库中,有一堆本地包;也就是说,这些包是在 lib 中定义的,使用本地路径依赖格式 .package(p
我想在工作中学习和使用nodejs,但是在使用 de npm 命令安装模块/包时遇到网络问题。我是否可以使用我的家用计算机构建完整的 Node js 包,然后将其安装在另一台计算机(我的工作场所计算机
我需要将一些 .tar.bz2 格式的非 Python 包转换为 Anaconda/miniConda .egg 文件并安装它们。为此,我需要一个适用于 Windows 的 bld.bat 文件。互联
我需要共享库文件 libthrift-0.9.3.so 作为其他包的依赖项。我在构建 thrift-0.9.3 包时看到编译问题(我确实从 https://thrift.apache.org/down
我尝试在 R 版本 3.5.0 中安装“arcgisbinding”包。但是我失败了,得到以下错误和警告。 Installing package into ‘C:/Users/Lenovo/Docum
我尝试在 R 版本 3.5.0 中安装“arcgisbinding”包。但是我失败了,得到以下错误和警告。 Installing package into ‘C:/Users/Lenovo/Docum
我试图在 flutter 中测试这个应用程序,但我无法运行该应用程序,因为出现此错误“名称‘Page’在库‘package:burn_off/widgets/page.dart’和‘package’中
试图理解和学习如何编写包...用我一直使用的东西进行测试,记录... 您能帮我理解为什么“日志”变量不起作用...并且屏幕上没有日志记录吗? 谢谢! 主要文件: #!/opt/local/bin/py
我尝试运行此使用 Google 云的代码。 import signal import sys from google.cloud import language, exceptions # creat
我想知道是否有人找到了一个很好的 R 包来分析眼动追踪数据? 我遇到了 eyetrackR,但据我所知,没有可用的英文支持文档: http://read.psych.uni-potsdam.de/pm
我正在 R 上制作一个包。我有两个函数共享一个变量(全局)。 如何将其导入到包中? 例如, m<-0 f<-function() { m <- m+1 } g<-function() { m <- m
我用 C 为 Lua 编写了很多模块。每个模块都包含一个 Lua 用户数据类型,我像这样加载和使用它们: A = require("A") B = require("B") a = A.new(3,{
我正在尝试在 R 中的 Ubuntu 上安装 xlsx 包,以便使用允许在 R 中插入链接然后将它们导出到 Excel 的功能。 话虽如此,我根本无法安装该软件包。 显然它必须与 rJava 一起使用
我想在 Haskell 中做一些蒙特卡洛分析。我希望能够编写这样的代码: do n <- poisson lambda xs <- replicateM n $ normal mu sigma
我是一名优秀的程序员,十分优秀!