什么是参数值的尖括号,它的用途是什么?
我习惯使用尖括号来指定类型作为参数:
vector<int> vecOfInts ;
但是在 rapidjson 中,有代码如下:
document.Parse<0>(json) ;
document.Parse
方法的签名是:
template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
GenericStringStream<Encoding> s(str);
return ParseStream<parseFlags>(s);
}
我不知道您可以在尖括号内传递值 - 认为尖括号仅用于类型名称。
这里的代码在做什么,为什么他要在尖括号中传递一个值?
这是个好主意吗?什么时候?
I am used to angle brackets being used to specify a type, as a parameter:
vector<int> vecOfInts ;
But in rapidjson, there is code like this:
document.Parse<0>(json) ;
The document.Parse
method's signature is:
template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
GenericStringStream<Encoding> s(str);
return ParseStream<parseFlags>(s);
}
I didn't know you could pass a value inside angle brackets - thought angle brackets were used for typenames alone.
What is the code here doing, and why is he passing a value in the angle brackets?
Is this a good idea? When?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这里有两个不同的因素。
首先,可以定义对类型以外的事物进行参数化的模板。例如,这是一个简单的数组类型:
我们可以这样使用它:
我们知道
vector
和vector
是不同的类型。但现在我们还必须指出Array
和Array
是不同的类型。其次,使用模板时,编译器必须能够计算出所有模板参数的值。当您使用模板类时,这就是您通常指定所有模板参数的原因。例如,您不会说
vector x
,而是说类似vector; x。使用模板函数时,大多数时候编译器可以计算出参数。例如,要使用
std::sort
,您只需说类似的内容。但是,您也可以写得
更明确。但有时,您有一个模板函数,但并非所有参数都可以计算出来。在您的示例中,我们有:
请注意,不能仅从函数的参数中推导出
parseFlags
模板参数。因此,要调用该函数,您必须指定模板参数,否则编译器无法识别它。这就是为什么你会写这样的内容:Here,0 是模板参数(在编译时解析),而
myString
是实际参数(在运行时解析)。实际上,您可以拥有结合了一些类型推断和一些显式类型参数的方法。例如,在 Boost 中,有一个函数 lexical_cast 可以进行字符串类型的转换。从非字符串类型转换为字符串类型的函数签名是
Here,如果你调用
lexical_cast
,编译器可以找出Source
是什么,但它不能' t 在没有任何提示的情况下推断出Target
。因此,要使用 lexical_cast ,您需要编写类似的内容。更一般地说,编译器表示您必须指定一定数量的模板参数(可选 0),并且它将尝试推导其余部分。如果可以的话,太好了!如果不是,则是编译时错误。使用这个,如果你愿意,你可以编写一个像这样的函数
要调用这个函数,你必须像这样调用它:
在这里,这是有效的,因为你必须明确告诉编译器什么
IntArgument
是,但是编译器可以从DoSomething
的参数类型推断出TypeArgument
。希望这有帮助!
There are two different factors going on here.
First, it's possible to define templates that are parameterized over things other than just types. For example, here's a simple array type:
We can use this like
We know that
vector<int>
andvector<double>
are different types. But now we must also point out thatArray<int,137>
andArray<int,136>
are different types.Second, when using templates, the compiler has to be able to figure out a value for all of the template arguments. When you're using template classes, this is why you typically specify all the template arguments. You don't say
vector x
, for example, but instead say something likevector<double> x
. When using template functions, most of the time the compiler can figure out the arguments. For example, to usestd::sort
, you just say something likeHowever, you could also write
to be more explicit. But sometimes, you have a template function for which not all the arguments can be figured out. In your example, we have this:
Notice that the
parseFlags
template parameter can't be deduced from just the arguments of the function. As a result, to call the function, you must specify the template parameter, since otherwise the compiler can't figure it out. That's why you'd write something likeHere, the 0 is a template argument (resolved at compile-time), and
myString
is the actual argument (resolved at run-time).You can actually have methods that combine a bit of type inference and a bit of explicit type parameters. For example, in Boost, there's a function
lexical_cast
that can do conversions to and from string types. The function signature to convert from a non-string type to a string type isHere, if you call
lexical_cast
, the compiler can figure out whatSource
is, but it can't deduceTarget
without some hints. To uselexical_cast
, therefore, you'd write something likeMore generally, the compiler says that you have to specify some number of template arguments (optionally 0), and it will try to deduce the rest. If it can, great! If not, it's a compile-time error. Using this, if you'd like, you could write a function like
To call this function, you'd have to invoke it like this:
Here, this works because you have to explicitly tell the compiler what
IntArgument
is, but then the compiler can deduceTypeArgument
from the type of the argument toDoSomething
.Hope this helps!