将具有未知参数列表的可变参数模板类型定义为std :: map value type

时间:2017-08-18 04:53:55

标签: c++ types c++14 variadic-templates variadic-functions

我不确定这是否有可能在过去的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);
}

1 个答案:

答案 0 :(得分:0)

似乎你只需要:

class unit_test {
public:
    unit_test() = delete;
    unit_test(const std::string& group_name)
    : m_tm(), m_group_name(group_name)
    {

    }

    // Register an functor item
    void add_test(const std::string& name, std::function<void()> f) {
        m_tm.emplace(name, std::move(f));
    }

    void run() 
    {
        // ...
        for (const auto& t : m_tm) {
            // ...
            t.second->run();
            // ...
        }
    }

private:
    std::map<std::string, std::function<void()>> m_tm;
    std::string m_group_name;
};