可以在模板之外使用c ++ 11参数包吗? [英] Can c++11 parameter packs be used outside templates?

查看:112
本文介绍了可以在模板之外使用c ++ 11参数包吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道我是否可以包含由单个明确指定的类型组成的参数包。例如,如下所示:

I was wondering if I could have parameter packs consisting of a single, explicitly specified, type. For example, something like this:

#include <iostream>

using namespace std;

void show() { }

template<typename First, typename... Rest>
void show(First f, Rest... rest)
{
    cout << f << endl;
    show(rest...);
}

void foo(int f, int... args) // error
{
    show(f, args...);
}

int main()
{
    foo(1, 2, 3);
}

我遇到的问题是 foo()。使用OS X clang ++版本5(llvm 3.3svn)时出现错误错误:函数参数包的类型'int'不包含任何未扩展的参数包

The problem I'm having is with the definition of foo(). With OS X clang++ version 5 (llvm 3.3svn) I get the error error: type 'int' of function parameter pack does not contain any unexpanded parameter packs.

当然,我可以通过将 foo()更改为函数模板来进行编译:

Of course, I can get it to compile by changing to foo() into a function template:

template<typename... Args>
void foo(int f, Args... args)
{
    show(f, args...);
}

但是现在 foo()将接受第一个参数 int ,其余所有输出均可流式传输。例如:

However now foo() will accept int for the first parameter, and anything output streamable for the rest. For example:

struct x { };
ostream& operator<<(ostream& o, x)
{
    o << "x";
    return o;
}

int main()
{
    foo(1, 2, x(), 3); // compiles :(
}

现在,我见过此处接受的解决方案,建议使用类型特征和 std :: enable_if ,但这很麻烦。还建议使用 std :: array ,但是我认为一个简单的 std :: initializer_list 可以正常工作,看起来更干净,例如因此:

Now, I've seen the accepted solution here which suggests using type traits and std::enable_if, but that's cumbersome. They also suggested using std::array but I think a simple std::initializer_list works just fine and looks cleaner, like so:

void foo_impl(initializer_list<int> ints)
{
    for(int i: ints)
        cout << i << endl;
}

template<typename... Args>
void foo(int f, Args... args)
{
    foo_impl({f, args...});
}

struct x { };
ostream& operator<<(ostream& o, x)
{
    o << "x";
    return o;
}

int main()
{
    foo(1, 2, 3);
    foo(1, 2, x(), 3); // no longer compiles
                       // we also get an error saying no known conversion from 'x' to 'int' :)
}

这很整洁。但是问题仍然存在,这是否必要?真的没有办法定义一个接受特定类型参数包的非模板函数吗?像这样:

So that's neat. But the question remains, is this necessary? Is there really not a way to define a non-template function which accepts a parameter pack of specific type? Like this:

void foo(int... args) { }


推荐答案

void foo(int... args) {}

不,你不能这样写。

但是您可以用这种方法产生相同的效果:

But you can have the same effect with this approach:

template<typename ...Ints>
void foo(Ints... ints) 
{
   int args[] { ints... }; //unpack ints here
   //use args
}

使用这种方法,您可以根据需要传递所有 int 。如果传递给 foo 的任何参数不是 int 或不能转换为 int ,上面的代码将导致编译错误,因为如果允许,使用 int ... args 方法就是这种情况。

With this approach, you can pass all int if you want. If any argument passed to foo is not int or convertible to int, the above code will result in compilation error, as it would be the case with int ...args approach if it were allowed.

您还可以使用 static_assert 来确保所有 Ints 的确是 int 如果需要的话:

You could also use static_assert to ensure all Ints are indeed int if you want that behaviour:

template<typename ...Ints>
void foo(Ints... ints) 
{
   static_assert(is_all_same<int, Ints...>::value, "Arguments must be int.");

   int args[] { ints... }; //unpack ints here
   //use args
}

现在ve实现不难实现的 is_all_same 元功能。

Now you've to implement is_all_same meta-function which is not difficult to implement.

好的,这是基本思想。您可以使用可变参数模板以及一些实用程序元函数和辅助函数来编写更复杂的代码。

Alright, this is the basic idea. You can write more sophisticated code with variadic templates and with the help of some utility meta-functions and helper functions.

对于可变参数,您可以完成很多工作,您甚至不需要存储在 args [] 数组中,例如,如果要将参数打印到 std :: ostream ,那么您可以这样做:

For lots of work that you can do with variadic arguments, you don't even need to store in args[] array, e.g if you want to print the arguments to std::ostream, then you could just do it as:

struct sink { template<typename ...T> sink(T && ... ) {} };

template<typename ...Ints>
void foo(Ints... ints) 
{
    //some code

     sink { (std::cout << ints)... };
}

此处创建了 sink ,以便您使用列表初始化语法来解压缩模板参数。

Here you create a temporary object of type sink so that you use unpack the template arguments using list-initialization syntax.

最后,您可以只使用 std :: initializer_list< ; int> 本身:

Last you could just use std::initializer_list<int> itself:

void foo(initializer_list<int> const & ints) 
{

}

std: :vector< int> 以防万一,如果您需要在 foo()中使用类似矢量的行为。如果使用这些方法中的任何一个,则在调用该函数时必须使用 {}

Or std::vector<int> in case if you need vector-like behavior inside foo(). If you use any of these, you have to use {} when calling the function as:

f({1,2,3});

这可能并不理想,但我认为随着C ++ 11的到来,您会看到这样的代码

That may not be ideal but I think with the advent of C++11 you will see such code very frequently!

这篇关于可以在模板之外使用c ++ 11参数包吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆