已知类型的C++变分函数模板

C++ Variadic Function Templates of Known Type

本文关键字:函数模板 C++ 类型      更新时间:2023-10-16

我目前正试图了解使用可变模板支持可以做的一些事情。假设我有一个这样的功能-

template <typename ... Args>
void foo(Args ... a)
{
    int len = sizeof...(tail);
    int vals[] = {a...};
    /* Rest of function */
}
/* Elsewhere */
foo(1, 2, 3, 4);

这段代码之所以有效,是因为我事先假设参数将是整数,但如果我提供其他内容,显然会失败。如果我事先知道参数包将包含一个特定的类型,那么有没有什么方法可以在没有模板的情况下使用之类的东西

void foo(int ... a)

我试过这样做,但编译器给出了一个错误,即foo是一个空字段。我知道我也可以通过递归访问包中的参数,但我不确定这是否能解决我的问题——也就是说,我希望能够接受相同类型的可变数量的参数。

这应该有效:

void foo(int);
template<typename ...Args>
void foo(int first, Args... more)
{
   foo(first);
   foo(more...);
}

如果您以前知道类型,您可以使用std:initializer_list:的函数重载

#include <initializer_list>
#include <iostream>
void foo( std::initializer_list<int> l )
{
    for ( auto el : l )
        // do something
}
void foo( std::initializer_list<float> l )
{
}
void foo( std::initializer_list<std::string> l )
{
}
int main()
{
    foo( {1, 2, 3, 4 } );
    foo( {1.1f, 2.1f, 3.1f, 4.1f } );
    foo( { "foo", "bar", "foo", "foo" } );
    return 0;
}

如果使用Visual Studio 2012,则可能需要Visual C++编译器2012年11月版CTP

编辑:如果您仍然想使用可变模板,您可以执行:

template <int ... Args>
void foo( )
{
    int len = sizeof...(Args);
    int vals[] = {Args...};
    // ...
}
// And
foo<1, 2, 3, 4>();

但您必须记住,它不适用于floatstd::string,例如:您将以'float': illegal type for non-type template parameter结束。float作为non-type template parameter是不合法的,这与精度有关,浮点数无法精确表示,您引用同一类型的可能性可能取决于数字的表示方式。

我目前正试图了解一些我可以使用varadic模板支持做的事情。

假设你想用可变模板进行实验,但没有找到任何问题的解决方案,那么我建议你看看下面的代码:

#include <iostream>
template<int ...Values>
void foo2()
{
    int len = sizeof...(Values);
    int vals[] = {Values...};
    for (int i = 0; i < len; ++i)
    {
        std::cout << vals[i] << std::endl;
    }
}
int main()
{
    foo2<1, 2, 3, 4>();
    return 0;
}

foo2foo的区别在于,您在运行时将参数传递给foo,在编译时将参数传给foo2,因此对于您使用的每个参数集,编译器都会生成单独的foo2函数体。

顶部答案的变体,如果您喜欢,它将拒绝隐式转换为int

#include <type_traits>
void foo(int);
template<typename Arg1, typename ...Args>
void foo(Arg1 first, Args... more)
{
   static_assert(std::is_same_v<Arg1, int>, "foo called with non-int argument");
   foo(first);
   foo(more...);
}

在大多数情况下,使用具有相同类型参数包的可变模板是没有意义的,但在启用c++11的编译器中:

#include <iostream>
#include <tuple>
template <typename ... Args>
void foo(Args ... args) {
    using type = typename std::tuple_element<0, std::tuple<Args...>>::type;
    const auto len = std::tuple_size<std::tuple<Args...>> {};
    type vals[] = {args...};
    for (size_t it = 0; it < len; ++it) {
        std::cout << vals[it] << std::endl;
    }
}
int32_t main(int argc, char** argv) {
    foo(1, 2);
    foo(1.1, 2.2);
    foo("1", "2");
    return EXIT_SUCCESS;
}