【问题标题】:What is angle brackets for argument values, and what is it used for? [duplicate]什么是参数值的尖括号,它的用途是什么? [复制]
【发布时间】:2012-02-08 22:02:16
【问题描述】:

我习惯用尖括号来指定类型,作为参数:

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);
}

我不知道您可以在尖括号内传递 - 以为尖括号仅用于类型名。

这里的代码在做什么,为什么他在尖括号中传递一个

这是个好主意吗?什么时候?

【问题讨论】:

  • 查找“非类型模板参数”。

标签: c++ templates syntax


【解决方案1】:

这里有两个不同的因素。

首先,可以定义参数化的模板,而不仅仅是类型。例如,这是一个简单的数组类型:

template <typename T, size_t N> struct Array {
    T arr[N];
};

我们可以这样使用

Array<int, 137> myArray;

我们知道vector&lt;int&gt;vector&lt;double&gt; 是不同的类型。但是现在我们还要指出Array&lt;int,137&gt;Array&lt;int,136&gt;是不同的类型。

其次,当使用模板时,编译器必须能够计算出所有模板参数的值。当您使用模板类时,这就是您通常指定所有模板参数的原因。例如,您不要说vector x,而是说vector&lt;double&gt; 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 是什么,但是编译器可以从 DoSomething 的参数类型中推断出 TypeArgument

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 2015-08-07
    • 2011-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 2013-06-12
    • 1970-01-01
    • 2010-09-27
    相关资源
    最近更新 更多