我习惯用尖括号来指定类型,作为参数:
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);
}
我不知道您可以在尖括号内传递 值 - 以为尖括号仅用于类型名。
这里的代码在做什么,为什么他在尖括号中传递一个值?
这是个好主意吗?什么时候?
最佳答案
这里有两个不同的因素。
首先,可以定义参数化的模板,而不仅仅是类型。例如,这是一个简单的数组类型:
template <typename T, size_t N> struct Array {
T arr[N];
};
我们可以这样使用
Array<int, 137> myArray;
我们知道 vector<int>
和 vector<double>
是不同的类型。但现在我们还必须指出 Array<int,137>
和 Array<int,136>
是不同的类型。
其次,当使用模板时,编译器必须能够计算出所有模板参数的值。当您使用模板类时,这就是您通常指定所有模板参数的原因。你不说vector x
,例如,而是说 vector<double> x
.使用模板函数时,大多数时候编译器可以找出参数。例如,使用 std::sort
,你就说类似
std::sort(v.begin(), v.end());
不过,你也可以写
std::sort<vector<int>::iterator>(v.begin(), v.end());
更明确。但有时,您有一个模板函数,无法计算出所有参数。在你的例子中,我们有这个:
template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
GenericStringStream<Encoding> s(str);
return ParseStream<parseFlags>(s);
}
请注意 parseFlags
模板参数不能仅从函数的参数推导出来。因此,要调用该函数,您必须指定模板参数,否则编译器无法识别。这就是为什么你会写类似的东西
Parse<0>(myString);
这里,0 是模板参数(在编译时解析),myString
是实际参数(在运行时解析)。
您实际上可以拥有结合了一些类型推断和一些显式类型参数的方法。例如,在 Boost 中,有一个函数 lexical_cast
可以在字符串类型之间进行转换。从非字符串类型转换为字符串类型的函数签名是
template <typename Target, typename Source>
Target lexical_cast(const Source& arg);
这里,如果您调用 lexical_cast
,编译器可以找出 Source
是,但不能推导出Target
没有一些提示。使用 lexical_cast
,因此,你会写类似
std::string myString = boost::lexical_cast<std::string>(toConvertToString);
更一般地说,编译器说你必须指定一些模板参数(可选 0),它会尝试推断其余的。如果可以,那就太好了!如果不是,则为编译时错误。使用这个,如果你愿意,你可以写一个类似的函数
template <int IntArgument, typename TypeArgment>
void DoSomething(const TypeArgument& t) {
/* ... */
}
要调用这个函数,你必须像这样调用它:
DoSomething<intArg>(otherArg);
在这里,这是可行的,因为您必须明确告诉编译器 IntArgument
是,但是编译器可以推导出 TypeArgument
从参数类型到DoSomething
.
希望这会有所帮助!
关于c++ - 什么是参数值的尖括号,它的用途是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9202200/