【发布时间】:2018-01-26 16:14:33
【问题描述】:
我不确定这是否可能在过去 3 个小时内没有任何有意义的方法来实现。
我有一个这样的可变参数模板:
template<typename... Ts>
class xunit_test_item {
public:
template<typename F, typename... Args>
xunit_test_item(const std::string& name, F&& func, Args&&... args)
: m_name(name)
, m_f(std::forward<F>(func))
, m_args(std::forward<Args>(args)...)
{
}
// ...
private:
const std::string m_name;
std::function<void (Ts...) > m_f;
std::tuple<Ts...> m_args;
};
上面的模板包装了一个测试项目,它基本上是一个函子的持有者,带有传递的参数以及一个用于命名该项目的字符串。
该类型的对象必须作为值类型存储到 std::map 中。这是在一个类中处理的,该类包含一个std::map 容器作为成员、一个添加 xunit_test_item 项目的注册方法和一个 run 方法,该方法遍历映射并执行所有存储的 xunit_test_item 存储函数。
这个类看起来基本上是这样的:
class unit_test {
// Define a map type of xunit_test_items
template<typename ...Ts>
using testitem_map_t = std::map<size_t, xunit_test_item<Ts...>>;
public:
unit_test() = delete;
unit_test(const std::string& group_name)
: m_tm()
, m_group_name(group_name)
, m_test_id(0)
{
}
// Register an functor item
template<typename F, typename ...Args>
void add_test(const std::string& name, F&& fun, Args&& ...args) {
m_tm.emplace(++m_test_id, xunit_test_item<Args...>(
name, std::forward<F>(fun), std::forward<Args>(args)...));
}
void run()
{
// ...
for (auto& t : m_tm) {
// ...
t.second->run();
// ...
}
}
private:
testitem_map_t m_tm; // <-- Compiler correctly reports an error
std::string m_group_name;
size_t m_test_id;
};
我遇到的问题是找到正确的语法/不同的方法来将xunit_test_item 定义为m_tm 映射成员的值类型。上面的代码没有编译 - 毫无疑问 - 因为我必须为 m_tm 成员指定一个参数列表,其类型为 testitem_map_t。我不知道如何定义该类型并正确声明 m_tm 成员。此时参数列表是未知的。
也许我上面的课程有设计问题,我想知道是否有或多或少简单的方法来实现这一点。我也可能完全看不到一个简单的解决方案。
很乐意学习并得到好的建议。提前致谢!
更新
新鲜的一天,新鲜的尝试和一杯咖啡......
我使用 2 级 lambda 重构了 add_test 方法的主体,这似乎到目前为止有效。作为测试函数(实际的测试用例),我可以添加 lambdas、带有任意参数或根本没有参数的函数指针。
我不知道这是否是最好的解决方案,或者是否可以以更好的方式编码,也许有人想评论这个话题。也是我不输入这个作为答案的原因。我最初的问题是希望学习一些 C++14 糖作为解决方案……如果可能的话。
这是第一个粗略测试的版本...
template<typename F, typename ...Args>
void add_test(const std::string& name, F&& fun, Args&& ...args) {
std::function<void(Args...)> fun_xargs =
[name, fun](auto&&... args) {
std::cout << " inner lambda\n";
auto x = xunit_test_item<Args...>(name, fun, std::forward<Args>(args)...);
x.run();
};
std::function<void()> fun_void =
[=] {
std::cout << "outer lambda\n";
fun_xargs(args...);
};
m_tm.emplace(++m_test_id, fun_void);
}
【问题讨论】:
-
将
run包装在 lambda 中,并将其作为std::function<void()>存储在地图中 -
注意:
xunit_test_item::xunit_test_item的Args...参数只能解析为可转换为Ts...的包,因此您最好在此处使用Ts...。 -
@caleth:写得好!
-
@vu1p3n0x:我不太明白,当你的评论得到支持时,我很好奇……我插入的是
xunit_test_item,而不是函数。 -
您的
xunit_test_item会删除函子的类型,但不会删除参数类型。您需要删除两者。
标签: c++ types c++14 variadic-templates variadic-functions