Why std::get uses template parameter instead of regular parameter? - c++

The std::get function uses template parameter as a regular parameter.
As an example:
std::tuple <int, double, long &, const char *> bar(18, 6.5, 12, "Hello!");
cout << std::get<2>(bar); // Print the tuple’s third element.
Why this function designed this way?
Why not using a regular parameter instead?
For example, something like: std::get(bar, 2) or std::get(2, bar)

A function must have a well-defined return type, specified at compile time. Here the template specialisation get<2> is a function returning long&; but your version would have to return a different type depending on its argument, specified at runtime, which is impossible.

Hopefully, this demonstration is explanation enough:
int x;
std::cin >> x;
auto i = std::get(bar, x);
Keeping in mind that in C++ the type of any object must be known at compile time, what type is i? Note that you cannot pass variables as template arguments, you must pass constant expressions, so the above problem doesn't exist when the integer is a template argument.
Perhaps more relevant to your example is this.
std::cout << std::get(bar, x);
Each overload of operator<< is a different function. Which function to call is determined at compile time, based on the arguments. So how can the compiler determine which overload to call in the above statement? What if you had a tuple member which didn't even have an overload?

Related

C++ - Declare pointer to function returning any type and getting any number of parameters

I was wondering if writing anything resembling this declaration (making use of the parameter pack) is possible.
decltype(auto) (*funcPtr)(...);
If possible, I would also like to know about alternative ways to declare such a pointer.
C++ is a statically typed language. All function argument types and return types must be known at compile time. You cannot declare a function that returns arbitrary types (well, I guess you could return std::any, but I can't think of a case where you'd want to).
You can use templates, however, to create function templates where the compiler will stamp out multiple versions of a function for you, so you don't have to write them all yourself.
Remember that auto and decltype(auto) is not magic. They are just syntactic sugar for what you'd otherwise write yourself if they didn't exist. They do not enable any new features that weren't already in the language. They just make such features easier to use.
No, there is no type such as pointer to function "that returns anything". There are only pointers to a function that returns some type or void. auto merely deduces the type from an initialiser, and there is nothing to deduce the type from in your example.
You can however have a function template where the instance of the template is a function that returns a type specified by a template argument:
// function template
template<class T>
T foo() {
return {};
}
Likewise, you can have a variable template that is a pointer to function whose return type is specified by a template variable:
// variable template
template<class T>
T (*funcPtr)() = foo;
// example usage
int main() {
return funcPtr<int>();
}

How to create a get() member function for a std::tuple

My problem is std::tuple has no member function like
auto t = std::make_tuple(1,2,"foo");
t.get(1);
how can I implement such a function when I create a wrapper class arround std::tuple
Such a function cannot exist (in current C++ standards) because function arguments are a run-time mechanism, but return types need to be known at compile time. So the latter cannot depend on the former.
Use std::get instead:
auto v = std::get<1>(someTuple);
To get a value from a tuple you should use std::get<0>(tuple)
You can't have a get function like you want, because tuple elements are not necessarily of the same type (in your example you have ints and a string). What would the return type of this get function be?
You can add a template get function, so that derived_tuple.get<0>() will return the first element.
There are actually two questions here. The first is
why get has a template integral argument rather than a accepting this
value as a function argument.
This has been answered.
The other question is
why get is a free function rather than a member function
To this the answer seem to be - so that called on templated types, it would not require usage of keyword typename. Example. Suppose, tuple would have a get as a member, it would have to be called like that in below code:
template <class T> void foo(T tuple) {
tuple.template get<1>() = 42;
}
This template is certainly a nuisance.

std::function type and template instantiation

I'm new to C++ and I'm learning about lambdas,functors and callables, and I know that there's a wrapper class, namely std::function that allows callables of different types to be stored and called (as long as the have the same call signature,or function type).
Now, I understand that you can have function with function type parameters that are really just function pointer parameters as in :
void fun(int,int*(int,int&));
which is nothing more than a function that takes an int and a function pointer to a function like int *f(int,int&),even if the language allows me to pass a function as an argument (with or without the ampersand).Infact, the function parameter list might as well be written as:
void fun(int,int*(*)(int,int&));
Now,back to the std::function type
I know that I can instantiate std::function with a function type and that allows any kind of callable to be passed to the wrapper. But, a function type is not a type I can use as a template type argument in any instantiation such as:
std::vector<int(int)> f_vec;
instead, I should make a vector of function pointers
std::vector<int(*)(int)> f_vec;
and that would allow me to insert pointers to function,but not functors or lambdas.
So, my question is, how can I instantiate a template with a type argument like a function type?? what's happening under the hood in the library std::function type.I mean a function type seems to me a type I cannot use in templates?? pleas can you make things a little clearer,as I'm just beginning to learn these topics. Thanks
The reason why you cannot write std::vector<int(int)> is not something fundamental about using function types as template parameters. That's perfectly valid. It's just what std::vector<T> does with the T (like operate on it by value) which makes std::vector<int(int)> illegal.
This can be shown by using std::vector<int(int)> in a context where nothing bad happens, such as this:
typedef std::vector<int(int)> StillOk;
StillOk *p = nullptr;
As long as the template doesn't actually try to do anything illegal with int(int), it's fine.
So, as long as your template deals with its template parameter in a way which is legal for function types, you can use it with function types. Here's a hypothetical example:
template <class T>
struct MyPointer
{
T *p;
T& operator* () const { return *p; }
};
It's now perfectly legal to instantiate MyPointer<int(int)> and use its operator *, because it will only ever involve expressions of type int (*)(int) and int (&)(int). [Live example]
And that's pretty much also what std::function<T> does with its T—only things which are legal with a function type.

Pass a function template as a parameter in C++

For example, I want to get a list of maximum values from two sequences, left and right, and save the results in max_seq, which are all previously defined and allocated,
std::transform(left.begin(), left.end(), right.begin(), max_seq.begin(), &max<int>);
But this won't compile because the compiler says
note: template argument deduction/substitution failed
I know I can wrapper "std::max" inside a struct or inside a lambda. But is there a way directly use std::max without wrappers?
std::max has multiple overloads, so the compiler is unable to determine which one you want to call. Use static_cast to disambiguate and your code will compile.
static_cast<int const&(*)(int const&, int const&)>(std::max)
You should just use a lambda instead
[](int a, int b){ return std::max(a, b); }
Live demo
Template expansion and instanciation occur at compile time. So you can pass a template function only to templates.
You could pass an instanciated (templated) function at run-time (then it is an "ordinary" C++ function).

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

This question already has answers here:
Reason for using non-type template parameter instead of regular parameter?
(6 answers)
Closed 4 years ago.
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?
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!