可变参数模板将参数打包到std :: vector

时间:2020-04-28 18:25:51

标签: c++ templates variadic-templates

我是模板的新手,我真的不理解为什么这不起作用。我希望向量将使用这些值来构建。

main.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;
}

预期结果

1
2
3
4

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

3 个答案:

答案 0 :(得分:5)

您的代码中的问题在于T在此上下文中不是模板参数,而是模板参数包,在您的示例中将扩展为T=[int,int,int,int]std::vector希望将类型作为模板参数而不是模板参数包传递。您可以使用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;
    }
}

您应该注意,只有在传递给int_printf的参数具有通用类型的情况下,这才起作用。

答案 1 :(得分:3)

另一种较为罗word的方法是添加一个初始模板参数,指定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;
}

如果将不兼容类型的列表传递给int_printf,这可能会给出更清晰的错误消息。

答案 2 :(得分:2)

当您执行std::vector<T>时,T不是单一类型,而是一组类型。您不能将其用于向量,因为它需要元素的单一类型。

有两种方法可以解决此问题。首先是仅对向量的类型进行硬编码。这使代码的通用性降低,但由于您的函数名为int_printf而不是anything_print

,因此对您有用

另一种选择是使用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;
    }
}

您也可以使用fold expression并完全跳过向量

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

如果您只需要无限数量的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), ...);
}

现在您不能用int以外的任何函数来调用此函数,但是它可以根据需要任意多。