简体   繁体   English

std::vector 的 Variadic 模板打包参数

[英]Variadic template packed argument to std::vector

I'm new to templates and I don't really undestand why this doesn't work.我是模板的新手,我真的不明白为什么这不起作用。 I expected the vector to be constructed with those values.我希望用这些值构建向量。

main.cpp主.cpp


template <typename ...T>
void int_printf(T ...args)
{
    std::vector<T> vec = {args...};

    for(auto& v:vec)
    {
        std::cout << v << std::endl;
    }
}

int main()
{
    int_printf(1,2,3,4);

    return 0;
}

Expected result预期结果

1
2
3
4

Error by msvc compiler (translated) msvc 编译器出错(已翻译)

src/main.cpp(35): error C3520: 'T': the parameter pack must be expanded in this context
src/main.cpp(37): error C3536: '<begin>$L0': can't be used before initialization
src/main.cpp(37): error C3536: '<end>$L0': can't be used before initialization
src/main.cpp(37): error C2100: invalid redirection

The issue in your code, is that T is not a template parameter in this context, it is a template parameter pack, which would expand to T=[int,int,int,int] in your example.您的代码中的问题是T在此上下文中不是模板参数,它是模板参数包,在您的示例中将扩展为T=[int,int,int,int] std::vector expects a type to be passed as a template parameter, not a template parameter pack. std::vector期望将类型作为模板参数而不是模板参数包传递。 You can solve this issue by using std::common_type :您可以使用std::common_type解决此问题:

#include<type_traits>

template <typename ...T>
void int_printf(T ...args)
{
    //use std::common_type to deduce common type from template
    //   parameter pack
    std::vector<typename std::common_type<T...>::type> vec = {args...};

    for(auto& v:vec)
    {
        std::cout << v << std::endl;
    }
}

You should note, this will only work if the arguments passed to int_printf have a common type.您应该注意,这仅在传递给int_printf的 arguments 具有通用类型时才有效。

Another, slightly more wordy, way to do this is to add an initial template parameter specifying the type of vec , like so:另一种稍微冗长的方法是添加一个初始模板参数,指定vec的类型,如下所示:

#include <iostream>
#include <vector>

template <typename T, typename ... Args>
void int_printf(Args ... args)
{
    std::vector<T> vec = {args...};

    for (auto& v : vec)
    {
        std::cout << v << std::endl;
    }
}

int main()
{
    int_printf<int>(1,2,3,4);
    return 0;
}

This might give clearer error messages if you pass a list of incompatible types to int_printf .如果您将不兼容类型的列表传递给int_printf ,这可能会给出更清晰的错误消息。

When you do std::vector<T> , the T is not a single type but is instead is a pack of types.当您执行std::vector<T>时, T不是单一类型,而是一组类型。 You can't use that for the vector because it wants a single type for the element.您不能将其用于向量,因为它需要元素的单一类型。

There is a couple ways to handle this.有几种方法可以处理这个问题。 First would be to just hard code the type of the vector.首先是对向量的类型进行硬编码。 This makes the code less generic, but would work for you since your function is called int_printf and not anything_print这使代码不那么通用,但对您有用,因为您的 function 被称为int_printf而不是anything_print

Another option is to use std::common_type to get the common type of the elements like另一种选择是使用std::common_type来获取元素的通用类型,例如

template <typename ...T>
void int_printf(T ...args)
{
    std::vector<std::common_type_t<T...>> vec = {args...};

    for(auto& v:vec)
    {
        std::cout << v << std::endl;
    }
}

You could also use a fold expression and skip the vector entirely like您也可以使用折叠表达式并完全像跳过向量

template <typename ...T>
void int_printf(T ...args)
{
    ((std::cout << args << std::endl), ...);
//  ^^                                    ^
//  |          do this part         ^  ^  |
//  |              for each parameter  |  |
//  start fold expression          end fold
}

If you want just an unlimited number of int 's you could also use SFINAE to constrain the pack type to be integers like如果您只想要无限数量的int ,您还可以使用SFINAE将包类型限制为整数,例如

template <typename ...T, std::enable_if_t<std::conjunction_v<std::is_same<T, int>...>, bool> = true>
void int_printf(T ...args)
{
    ((std::cout << args << std::endl), ...);
}

and now you can't call this function with anything other than int 's but it can have as many as you want.现在你不能用除int以外的任何东西来调用这个 function 但它可以有你想要的任意数量。

You can use a std::variant in conjunction with std::vector .您可以将std::variantstd::vector结合使用。 Here is an example:这是一个例子:

template<typename... Args>
class VariantTest
{
private:
    using ArgTypes = std::variant<Args...>;
    std::vector<ArgTypes> elems;
public:
    VariantTest()
    {
        elems.reserve(10); //just a number
    }

    template<typename... ArgsL>
    void AddTypes(ArgsL&&... args)
    {
        (elems.emplace_back(std::forward<ArgsL>(args)), ...);
    }
    size_t GetElemsCount()
    {
        return elems.size();
    }
};

int main()
{

    VariantTest<A, B> vt;
    vt.AddTypes(B(), A()); //Note the order does not matter.
    std::cout << "Number of elements: " << vt.GetElemsCount() << '\n';
    return 0;
}

You will need C++17.您将需要 C++17。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM