c++ - 如何从具有同构模板类型参数的完美转发函数中提取模板类型?

标签 c++ templates variadic-templates stdvector perfect-forwarding

我希望编写一个可变参数工厂函数来转发可变数量的参数(相同类型)来构造和填充 std::vector 。但是我不确定如何从“完美转发”机制中提取元素的类型,因此由编译器自动推导此类型,并使用它来设置 vector 的类型。

本质上:

    template <typename T>
    struct Object { T x {}; };

    Object<int> x1 {1};
    Object<int> x2 {2};

    auto collection = make_objects(x1, x2, Object<int>(3));

    // 'collection' is a std::vector<Object<int>> with elements that are copies of x1, x2, and the third rvalue parameter. 

    // note that `make_objects` deduced all types it needed.

我正在使用 C++20 - 完整代码 here .


让我们从基本的具体结构开始:

struct Object {
    int x {};
};

我希望使用 std::vector 创建任意数量的集合。作为容器。我有一个名为 make_objects 的“工厂”函数它通过左值和/或右值获取可变数量的 Object 实例,并将它们完美转发到 vector 的 emplace_back()成员函数:

template <typename... Args>
auto make_objects(Args&&... args) {
    std::vector<Object> vec;
    vec.reserve(sizeof...(Args));
    (vec.emplace_back(std::forward<Args>(args)), ...);
    return vec;
}

这意味着客户端代码大多不知道集合类型(或者至少可以依赖 auto ),并且可以执行以下操作:

int main() {

    Object x1 {1};
    Object x2 {2};

    auto objects = make_objects(x1, x2, Object(3));

    for (auto o: objects) {
        std::cout << o << '\n';
    }
}

到目前为止一切顺利。

现在我想做我的Object通过将其转换为模板更通用,因此我将其更改为:

template <typename T>
struct Object {
    T x {};
};

此时我对如何编写make_objects感到困惑工厂功能。我的第一次尝试是:

template <typename T, typename... Args>
auto make_objects(Args&&... args) {
    std::vector<T> vec;  // how to specify this type?
    vec.reserve(sizeof...(Args));
    (vec.emplace_back(std::forward<Args>(args)), ...);
    return vec;
}

除非使用显式 T 调用,否则不会编译。 ,即make_objects<Object<int>> 。否则类型 T 不可推导。

有没有一种方法可以实现这种完美的转发,以便可以提取正在转发的同类类型并在转发函数中使用?

请注意,我希望避免使用以下类型的语法:

make_objects<int>(x, ...) - 我希望从参数中推断出对象的类型,但它们至少都是相同的类型(也许 std::same_asstd::convertible_to 可以在这里使用来强制执行?)。

make_objects({x, ...}) - 我不想在这种情况下使用初始化列表,因为最终我需要参数是非常量的,因为为了清楚起见,我省略了预期的副作用。

我一直在学习Homogeneous function parameter packs但这似乎遇到了同样的问题,因为如果Obj一切正常是一个具体的类,但没有提供关于如何处理模板化 Obj<T> 的线索(我已经注意到) .

最佳答案

make_objects 可以简单地是:

template <typename... Args>
auto make_objects(Args&&... args) {
    // use the std::vector deduction guide:
    return std::vector{std::forward<Args>(args)...};
}

然后,这将起作用:

int main() {
    Object x1 {1};
    Object x2 {2};

    auto objects1 = make_objects(x1, x2);

    //auto objects2 = make_objects(x1, x2, Object{3});   // C++17
    auto objects2 = make_objects(x1, x2, Object(3));
    
    for (auto o: objects2) {
        std::cout << o << '\n';
    }
}

如果您希望 Object{3} 在 C++17 中工作,请添加推导指南:

template<class T> Object(T) -> Object<T>;

关于c++ - 如何从具有同构模板类型参数的完美转发函数中提取模板类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75569524/

相关文章:

C++ 单引号语法

c++ - 部分普通旧数据

c++ - 如何通过索引从可变模板参数包中提取值?

c++ - 隐式模板参数无效,但仍可编译

c++ - 用户定义的字符串文字,字符串是否终止?

c++ - C中数据的功能责任

c++ - 引用初始化无效

c++ - 在它自己的指针上模板化一个类?

c++ - 内部模板类型 std::vector<std::vector<T>> 的函数模板重载或专门化

c++ - 使用自动说明符获取 lambda 的参数类型