sta*_*exi 24 c++ templates c++11
我想知道我是否可以使用由明确指定的单一类型组成的参数包.例如,像这样:
#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);
}
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是定义foo().使用OS X clang ++版本5(llvm 3.3svn)我收到错误error: type 'int' of function parameter pack does not contain any unexpanded parameter packs.
当然,我可以通过更改foo()为函数模板来编译它:
template<typename... Args>
void foo(int f, Args... args)
{
show(f, args...);
}
Run Code Online (Sandbox Code Playgroud)
但是现在foo()将接受int第一个参数,其余的任何输出都可以流式传输.例如:
struct x { };
ostream& operator<<(ostream& o, x)
{
o << "x";
return o;
}
int main()
{
foo(1, 2, x(), 3); // compiles :(
}
Run Code Online (Sandbox Code Playgroud)
现在,我已经看到了这里接受的解决方案,建议使用类型特征std::enable_if,但这很麻烦.他们还建议使用,std::array但我认为一个简单的std::initializer_list工作很好,看起来更干净,像这样:
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' :)
}
Run Code Online (Sandbox Code Playgroud)
这很整洁.但问题仍然存在,这是必要的吗?真的没有办法定义一个接受特定类型参数包的非模板函数吗?像这样:
void foo(int... args) { }
Run Code Online (Sandbox Code Playgroud)
Naw*_*waz 22
void foo(int... args) {}
Run Code Online (Sandbox Code Playgroud)
不,你不能写那个.
但是你可以用这种方法产生同样的效果:
template<typename ...Ints>
void foo(Ints... ints)
{
int args[] { ints... }; //unpack ints here
//use args
}
Run Code Online (Sandbox Code Playgroud)
使用这种方法,您可以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
}
Run Code Online (Sandbox Code Playgroud)
现在你要实现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)... };
}
Run Code Online (Sandbox Code Playgroud)
在这里,您可以创建一个类型的临时对象,sink以便使用list-initialization语法解压缩模板参数.
最后你可以std::initializer_list<int>自己使用:
void foo(initializer_list<int> const & ints)
{
}
Run Code Online (Sandbox Code Playgroud)
或者std::vector<int>如果您需要内部的矢量行为foo().如果您使用其中任何一个,则必须{}在调用函数时使用:
f({1,2,3});
Run Code Online (Sandbox Code Playgroud)
这可能不太理想,但我认为随着C++ 11的出现,你会经常看到这样的代码!
与 Brian 的回答一样,我意识到这最初是针对 C++11 的,但在 C++20 中,这可以使用概念以非常简单的方式解决:
#include <concepts>
void f(std::integral auto... ints)
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
std::integral接受任何整数类型,所以它更通用一些,如果可以接受的话。如果没有,您可以执行以下操作:
#include <concepts>
template<class T>
concept exactly_int = std::same_as<int,T>;
void f(exactly_int auto... ints)
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
为了对此添加更多解释,auto本质上是一个隐式模板,并且它之前的名称限制了允许的类型。因此,在第一个示例中,任何满足std::integral( int、long、unsigned、char等) 的内容都将被允许。第二个只允许ints,因为这是唯一满足所定义概念的类型。
有一种更简单的方法可以做到这一点:用作约束时的概念使用受约束的类型作为其第一个参数,因此您可以简单地编写:
#include <concepts>
void f(std::same_as<int> auto... ints)
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8004 次 |
| 最近记录: |