可以在模板外使用c ++ 11参数包吗?

  发布于 2023-02-12 16:30

我想知道我是否可以使用由明确指定的单一类型组成的参数包.例如,像这样:

#include 

using namespace std;

void show() { }

template
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)我收到错误error: type 'int' of function parameter pack does not contain any unexpanded parameter packs.

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

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

但是现在foo()将接受int第一个参数,其余的任何输出都可以流式传输.例如:

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工作很好,看起来更干净,像这样:

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

template
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' :)
}

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

void foo(int... args) { }

Nawaz.. 22

void foo(int... args) {}

不,你不能写那个.

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

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

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

您还可以使用static_assert以确保所有内容Ints确实int如果您想要这种行为:

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

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

现在你要实现is_all_same不易实现的元函数.

好吧,这是基本的想法.您可以使用可变参数模板编写更复杂的代码,并借助一些实用程序元函数和辅助函数.

对于你可以使用可变参数进行的大量工作,你甚至不需要存储在args[]数组中,例如,如果你想打印参数std::ostream,那么你可以这样做:

struct sink { template sink(T && ... ) {} };

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

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

在这里,您可以创建一个类型的临时对象,sink以便使用list-initialization语法解压缩模板参数.

最后你可以std::initializer_list自己使用:

void foo(initializer_list const & ints) 
{

}

或者std::vector如果您需要内部的矢量行为foo().如果您使用其中任何一个,则必须{}在调用函数时使用:

f({1,2,3});

这可能不太理想,但我认为随着C++ 11的出现,你会经常看到这样的代码!

1 个回答
  • void foo(int... args) {}
    

    不,你不能写那个.

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

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

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

    您还可以使用static_assert以确保所有内容Ints确实int如果您想要这种行为:

    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
    }
    

    现在你要实现is_all_same不易实现的元函数.

    好吧,这是基本的想法.您可以使用可变参数模板编写更复杂的代码,并借助一些实用程序元函数和辅助函数.

    对于你可以使用可变参数进行的大量工作,你甚至不需要存储在args[]数组中,例如,如果你想打印参数std::ostream,那么你可以这样做:

    struct sink { template<typename ...T> sink(T && ... ) {} };
    
    template<typename ...Ints>
    void foo(Ints... ints) 
    {
        //some code
    
         sink { (std::cout << ints)... };
    }
    

    在这里,您可以创建一个类型的临时对象,sink以便使用list-initialization语法解压缩模板参数.

    最后你可以std::initializer_list<int>自己使用:

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

    或者std::vector<int>如果您需要内部的矢量行为foo().如果您使用其中任何一个,则必须{}在调用函数时使用:

    f({1,2,3});
    

    这可能不太理想,但我认为随着C++ 11的出现,你会经常看到这样的代码!

    2023-02-12 16:32 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有