【问题标题】:Unpacking variadic template parameters into initializer list将可变参数模板参数解包到初始值设定项列表中
【发布时间】:2018-07-21 04:45:40
【问题描述】:

我目前正在尝试实现一个通用初始化程序来减少我们代码库的大小。然而,在某一时刻,我的代码看起来像这样:

template<typename T, typename Arg1, typename Arg2>
T* ManageDevice(Arg1 arg1, Arg2 arg2)
{
    auto device = new T{ arg1, arg2 };
    // More operations on device
    return device;
}

template<typename T, typename Arg1, typename Arg2, typename Arg3>
T* ManageDevice(Arg1 arg1, Arg2 arg2, Arg3 arg3)
{
    auto device = new T{ arg1, arg2, arg3 };
    // More operations on device
    return device;
}

template<typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
T* ManageDevice(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
{
    auto device = new T{ arg1, arg2, arg3, arg4 };
    // More operations on device
    return device;
}

这开始变得不那么优雅了。据我了解,可变参数模板似乎是解决此问题的方法。但我不明白这如何适用于我的情况。

我更喜欢这样的:

T* ManageDevice(Args... args)
{
    // The function I want
    // Unpack as a std::initializer_list
    auto allArguments = unpackAll(); 

    auto device = new T{ allArguments };
    // More operations on device
    return device;
}

关于如何实现 unpackAll() 有什么建议吗? 谢谢。

【问题讨论】:

  • 为什么不直接传呢? new T{ args...};,你可能想设置转发。

标签: c++ c++11 templates variadic-templates


【解决方案1】:
auto device = new T{ allArguments };

只是需要

auto device = new T{ args... };

T{ args... }args... 中会将参数包扩展为arg0, arg1, ..., argn

你可以看到这个工作

template <typename... Args>
std::vector<int> make_vector(Args... args)
{
    return {args...};
}

int main()
{
    auto foo = make_vector(1,2,3,4);
    for (auto e : foo)
        std::cout << e << " ";
}

编辑添加完美转发版本

template <typename... Args>
std::vector<int> make_vector(Args&&... args)
{
    return {std::forward<Args>(args)...};
}

【讨论】:

  • 好吧,这太简单了...谢谢!!
  • @JuBonn 没问题。如果你想使用完美转发,它会变得有点复杂,但不是很复杂。
【解决方案2】:

我的 C++14 答案,作为一个最小的工作示例

#include <initializer_list>
#include <utility>
#include <vector>
#include <type_traits>
#include <iostream>

struct example {
    template <typename ...Args, typename T = std::common_type_t<Args...>>
    static std::vector<T> foo(Args&& ...args) {
        std::initializer_list<T> li{std::forward<Args>(args)...};
        std::vector<T> res{li};
        return res;
    }
};

int main() {
    std::vector<int> v1 = example::foo(1,2,3,4);
    for(const auto& elem: v1)
        std::cout << elem << " ";
    std::cout << "\n";
}

您需要根据您的需要对它进行一些编辑,即您的代码结构。但请注意 vectorconstructor 采用 initializer_list 并且该列表是从静态 foo 方法中的参数包生成的。

编辑:在您的情况下,正如其他人指出的那样,您可以直接将您的参数包转发给您的电话。我的回答显示将它们传递给initializer_list

所以事实上,你可以这样做

static std::vector<T> foo(Args&& ...args) {
    std::vector<T> res{std::forward<Args>(args)...};
    return res;
}

这些参数将被隐式转换为initializer_list。我明确展示了从参数包中构造initializer_list

【讨论】:

  • 你为什么不能像 NathanOliver 所说的那样,return {args...}?我认为您的方式不会有任何开销,因为临时将被省略,但它仍然是多余的 IMO。
  • 是的,它是多余的。其想法是明确展示如何从参数包创建 initializer_list,而不是通过 std::vector 构造函数隐式创建。
猜你喜欢
  • 1970-01-01
  • 2013-12-02
  • 1970-01-01
  • 2013-04-07
  • 2017-03-07
  • 1970-01-01
  • 2017-05-15
  • 1970-01-01
  • 2022-11-20
相关资源
最近更新 更多