Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is angle brackets for argument values, and what is it used for? [duplicate]

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?

like image 796
bobobobo Avatar asked Feb 08 '12 22:02

bobobobo


People also ask

What are angle brackets used for?

An angle bracket or angle brace or angle cleat is an L-shaped fastener used to join two parts generally at a 90 degree angle. It is typically made of metal but it can also be made of wood or plastic. The metallic angle brackets feature holes in them for screws.

What are angle brackets used for in C++?

angular brackets are used for global use of the header files which are predefined and we include in our program. When you use angle brackets, the compiler searches for the file in the include path list. Angular brackets are used for standard inclusions.

Which brackets are used to give function arguments?

Almost all functions require arguments enclosed in parentheses and separated by commas. If arguments are required, do not place any spaces between the function name and the left parenthesis.

What does angle bracket mean in typescript?

One within the parentheses () and another within the angle brackets < > We know in the function call func(12) , argument 12 within the parentheses represents the arg parameter. Similarly in func<number>(12) , the argument number within the angle brackets represents the generic type parameter T .


1 Answers

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:

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

We can use this like

Array<int, 137> myArray;

We know that vector<int> and vector<double> are different types. But now we must also point out that Array<int,137> and Array<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 like vector<double> x. When using template functions, most of the time the compiler can figure out the arguments. For example, to use std::sort, you just say something like

std::sort(v.begin(), v.end());

However, you could also write

std::sort<vector<int>::iterator>(v.begin(), v.end());

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:

template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str) {
    RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
    GenericStringStream<Encoding> s(str);
    return ParseStream<parseFlags>(s);
}

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 like

Parse<0>(myString);

Here, 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 is

template <typename Target, typename Source>
    Target lexical_cast(const Source& arg);

Here, if you call lexical_cast, the compiler can figure out what Source is, but it can't deduce Target without some hints. To use lexical_cast, therefore, you'd write something like

std::string myString = boost::lexical_cast<std::string>(toConvertToString);

More 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

template <int IntArgument, typename TypeArgment>
    void DoSomething(const TypeArgument& t) {
       /* ... */
}

To call this function, you'd have to invoke it like this:

DoSomething<intArg>(otherArg);

Here, this works because you have to explicitly tell the compiler what IntArgument is, but then the compiler can deduce TypeArgument from the type of the argument to DoSomething.

Hope this helps!

like image 159
templatetypedef Avatar answered Oct 06 '22 07:10

templatetypedef