Determining the type of an expression - c++

Sometimes I need to learn the type of an expression while programming in C or C++. Sometimes there's a good IDE or existent documentation to help me, but sometimes not. I often feel such a construct could be useful:
void (*myFunc)(int);
printf("%s", nameoftype(myFunc)); //"void (*)(int)"
int i, unsigned int u;
printf("%s", nameoftype(i+u)); //"unsigned int"
This is especially true for C++; think accessors of const objects - do they return a const reference or a copy? Think dynamic casts and templated classes.
How can I do this? (i.e. learn the type of an expression)
I use GCC but as far as I know, it does not have such an extension. So I guess I'm curious as to how people solve this problem. (Both compile-time and runtime solutions welcome.)

Sometimes I just do:
int ***a = expression;
and look for the "<expression type> cannot be assigned to pointer-to^3 int" error. This seems to be the most portable workaround.

C++ has a typeid operator;
typeid(expression).name()
would return an implementation-defined name of the type of the expression. Alas, it is usually not human-readable.

What are you looking for? Automatic type inference or looking for the type so you can declare a variable correctly manually? (your own answers look like you want to have the second one). In this case, consider using Geordi:
<litb> make type pointer to function taking pointer to array of 10 int returning void
<geordi> void (*)(int (*)[10])
<litb> geordi: { int a = -1; unsigned int b = 0; cout << ETYPE(a + b), ETYPE_DESC(a + b), (a + b); }
<geordi> rvalue unsigned int, rvalue unsigned integer, 4294967295
<litb> geordi: << TYPE_DESC(void (*)(int (*)[10]))
<geordi> pointer to a function taking a pointer to an array of 10 integers and returning nothing
Automatic type inference is not currently possible without helper libraries like boost.typeof, which will use compiler extensions like __typeof__ for GCC. Next C++ will get auto (with different semantics than current auto) and will be able to do that, together with decltype to get the type of an expression.
If you can live with getting out of local context, you can always create a function template like this:
template<typename T> void f(T t) { /* ... */ }
int main() { int a = -1; unsigned int b = 0; f(a + b); }

Try Boost.Typeof to see if it fits.

gcc has typeof() at compile time. It works like sizeof().
http://gcc.gnu.org/onlinedocs/gcc/Typeof.html has more information.

Related

Is there any generic conversion from std::string to numeric type?

There are many ways to convert strings to numbers in C++: stoi, stod, stof, etc. Just like how std::invoke is a nice way to call any callable, I am looking for a method that converts string value to a generic numeric value.
For instance, instead of something like this:
int x = std::stoi("5");
long y = std::stol("5555555555");
Something like this:
int x = num_convert("55");
long y = num_convert("5555555555");
Is there any standard functionality for what I am trying to do?
This can be considered as a generic conversion:
#include<sstream>
int main() {
int x;
std::stringstream("55") >> x;
long y;
std::stringstream("5555555555") >> y;
}
A function can return only a single type, thus long y = num_convert("5555555555") with a regular function is impossible.
One more hack, help the function to deduce the returned type with the unused parameter:
#include <string>
template<typename T>
T num_convert(const char* s, const T&) {
return static_cast<T>(std::stoll(s));
}
int main() {
int x = num_convert("55", x);
long y = num_convert("5555555555", y);
}
What you want is not (easily) viable in C++. The return value of a function is defined by the function name and the arguments it is given (ie: the result of overload resolution). Your hypothetical num_convert("55") and num_convert("5555555555") expressions both take the same argument type. Therefore, they must (usually) call the same function which returns the same value.
Thus, the simplest way to achieve what you want would be for such a function to return a proxy object that stores the argument it is given. The proxy would have conversion operators (operator int, operator long, etc) which would perform the actual conversion.
Of course, this means that auto i = num_convert("55") will not actually do the conversion. If the function was given a temporary, i would contain a reference to that temporary. Which means that any uses of i would be broken, since they would reference a temporary whose lifetime has ended.
The standard doesn't have a function like this.
It would be better to write the type explicitly into the call as a template parameter and then use auto deduction instead of using a proxy: auto i = num_convert<int>("55");. The standard has no such function either. But really, there's not much difference between num_convert<int> and stoi, so just use it.
If you have boost then just use
boost::lexical_cast in Boost.Lexical_Cast 1.0
boost::cnv::lexical_cast in Boost.Convert 2.0
auto x = boost::lexical_cast<short>("5"s);
auto y = boost::lexical_cast<long>("5555555555"s);
Demo on Godbolt
You can also roll out your own lexical_cast like what boost did, if you don't want to use it
For more information read Boost.LexicalCast

How to cast from const void* in a constexpr expression?

I'm trying to reimplement memchr as constexpr (1). I haven't expected issues as I have already successfully done the same thing with strchr which is very simmilar.
However both clang and gcc refuse to cast const void* to anything else within constexpr function, which prevents me to access the actual values.
I understand that working with void* in constexpr function is weird, as we cannot do malloc and there is no way to specify arbitrary data as literal values. I'm doing this basically as a part of an excercise to rewrite as much as I can from as constexpr (2).
Still I'd like to know why this is not allowed and if there is any way around it.
Thank you!
(1) My implementation of memchr:
constexpr void const *memchr(const void *ptr, int ch, size_t count) {
const auto block_address = static_cast<const uint8_t *>(ptr);
const auto needle = static_cast<uint8_t>(ch);
for (uintptr_t pos{0}; pos < count; ++pos) {
auto byte_address = block_address + pos;
const uint8_t value = *byte_address;
if (needle == value) {
return static_cast<void const *>(byte_address);
}
}
return nullptr;
}
(2) The entire project on Github: https://github.com/jlanik/constexprstring
No, it is impossible to use void* in such a way in constant expressions. Casts from void* to other object pointer types are forbidden in constant expressions. reinterpret_cast is forbidden as well.
This is probably intentional to make it impossible to access the object representation at compile-time.
You cannot have a memchr with its usual signature at compile-time.
The best that I think you can do is write the function for pointers to char and its cv-qualified versions, as well as std::byte (either as overloads or as template), instead of void*.
For pointers to objects of other types it is going to be tricky in some cases and impossible in most cases to implement the exact semantics of memchr.
While I am not certain that it is possible, maybe, in a templated version of memchr, one can read the underlying bytes of the objects passed-by-pointer via a std::bit_cast into a struct containing a std::byte/unsigned char array of appropriate size.

Is it legal c++ to use reference as array/pointer?

My team (including myself) is new to C++. A piece of our new development is a C++ function that needs to interface with a C function that takes an array as input. Something like the following construct was made to achieve this:
#include "stdio.h"
void the_c_function(double *array, int len)
{
for (int i = 0; i < len; i++)
{
printf("%d: %g\n", i, array[i]);
}
}
void the_cpp_wrapper(double& dref, int len)
{
the_c_function(&dref, len);
}
int main()
{
const int LEN = 4;
double dbl_array[LEN] = { 3,4,5,6 };
the_cpp_wrapper(dbl_array[0], LEN);
return 0;
}
When compiled, this works as expected: it prints the contents of the array:
0: 3
1: 4
2: 5
3: 6
But this feels hardly legal to me or at the best something that should be discouraged.
Is this legal C++, i.e. is it guaranteed that a pointer to a reference of an array points to the original array?
Is there any reason why one would do it like this instead of using a pointer directly instead of using the reference as inbetween?
My team (including myself) is new to C++. ...
[...]
... something that should be discouraged.
You should get in the habit now of using the Standard C++ Library, in your case the best choice is std::vector:
#include <stdio.h>
#include <stdlib>
#include <vector>
void the_c_function(const double *array, size_t len) {/*...*/}
void the_cpp_wrapper(const std::vector<double>& v)
{
the_c_function(v.data(), v.size());
}
// ----------------------------
int main()
{
const std::vector<double> dbl_array { 3,4,5,6 };
the_cpp_wrapper(dbl_array);
return EXIT_SUCCESS;
}
You also should be clearer about const double* vs. double*, C++ intentionally wants you to use a much more verbose const_cast<double*> to cast-away const-ness.
If you want to go "all in" with C++, you can make the_cpp_wrapper() a bit more generic with a template:
template<typename TSpan>
void the_cpp_wrapper(const TSpan& v)
{
the_c_function(v.data(), v.size());
}
With this code, you can pass anything to the_cpp_wrapper that has data() and size() methods. (Note that TSpan "can" be std::span<int> which could cause some obscure compiler errors; there are ways to fix that, but it's more C++.)
Not directly related, but you'll probably find std::span useful too.
The question of code readability aside,
is it guaranteed that a pointer to a reference of an array points to the original array?
Yes, see § 5.5 Expressions:
If an expression initially has the type “reference to T” ([dcl.ref], [dcl.init.ref]), the type is adjusted to T prior to any further analysis. The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression.
And §8.3.2 References:
4   It is unspecified whether or not a reference requires storage.
5   There shall be no references to references, no arrays of references, and no pointers to references.
In other words, an "address of a reference" isn't a thing; given double& dref, taking an address &dref will give the address of the original element inside the array.
Yes it is legal and it is guaranteed to reference to the original element in the array based on your code.
Some people like to design interface to force the caller to pass by reference to avoid checking whether the argument is a null pointer, which might be required when passing by pointer.

How auto is deducing pointer type?

In below code I could not understand how auto comes to know that thing on right hand side is pointer :
int x = 100;
int *ptr = & x;
auto test = ptr;
std::cout<<*test<<std::endl;
Because as per my understanding pointer contains address which is nothing but unsigned int so how auto deduces it to be pointer but not unsigned int?
you can also ask the question "eventually, everything in my program is bytes, so why does auto doesn't deduce everything to be uint8_t[]?"
Well, it's simple. the type of ptr is int* so the type of test is also int*. it doesn't matter how the generated assembly looks like. it may be that the cpu treats int* and unsigned int the same way, but that's irrelevant for C++, as C++ is a high level language.
besides that. the underlying statement that "a pointer is an unsigned int" is not true. pointer is a type that allows reading and writing to the memory address contained in that variable. an unsigned int is ... an unsigned int. nothing more, nothing less.
The standard says:
The type of a variable declared using auto is deduced from its initializer.
Thus, the type of test is deduced from the one of ptr (that is its initializer) and it's int *.
Note that auto follows almost the same rules of template type deduction.
You can refer to them for further details about the differences between auto, auto&, const auto &, auto&& and so on.

What are the distinctions between the various symbols (*,&, etc) combined with parameters? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
c++ * vs & in function declaration
I know that this probably seems like an incredibly elementary question to many of you, but I have genuinely had an impossible time finding a good, thorough explanation, despite all my best Googling. I'm certain that the answer is out there, and so my search terms must be terrible.
In C++, a variety of symbols and combinations thereof are used to mark parameters (as well as arguments to those parameters). What, exactly, are their meanings?
Ex: What is the difference between void func(int *var) and void func(int **var)? What about int &var?
The same question stands for return types, as well as arguments. What does int& func(int var) mean, as compared to int* func(int var)? And in arguments, how does y = func(*x) differ from y = func(&x)?
I am more than happy to read enormous volumes on the subject if only you could point me in the right direction. Also, I'm extremely familiar with general programming concepts: OO, generics/templates, etc., just not the notation used in C/C++.
EDIT: It seems I may have given the impression that I do not know what pointers are. I wonder how that could be :)
So for clarification: I understand perfectly how pointers work. What I am not grasping, and am weirdly unable to find answers to, is the meaning of, for example 'void func(int &var)'. In the case of an assignment statement, the '&' operator would be on the right hand side, as in 'int* x = &y;', but in the above, the '&' operator is effectively on the left hand side. In other words, it is operating on the l-value, rather than the r-value. This clearly cannot have the same meaning.
I hope that I'm making more sense now?
To understand this you'll first need to understand pointers and references. I'll simply explain the type declaration syntax you're asking about assuming you already know what pointers and references are.
In C, it is said that 'declaration follows use.' That means the syntax for declaring a variable mimics using the variable: generally in a declaration you'll have a base type like int or float followed something that looks like an expression. For example in int *y the base type is int and the expression look-alike is *y. Thereafter that expression evaluates to a value with the given base type.
So int *y means that later an expression *y is an int. That implies that y must be a pointer to an int. The same holds true for function parameters, and in fact for whole function declarations:
int *foo(int **bar);
In the above int **bar says **bar is an int, implying *bar is a pointer to an int, and bar is a pointer to a pointer to an int. It also declares that *foo(arg) will be an int (given arg of the appropriate type), implying that foo(arg) results in a pointer to an int.¹ So the whole function declaration reads "foo is a function taking a pointer to a pointer to an int, and returning a pointer to an int."
C++ adds the concept of references, and messes C style declarations up a little bit in the process. Because taking the address of a variable using the address-of operator & must result in a pointer, C doesn't have any use for & in declarations; int &x would mean &x is an int, implying that x is some type where taking the address of that type results in an int.² So because this syntax is unused, C++ appropriates it for a completely different purpose.
In C++ int &x means that x is a reference to an int. Using the variable does not involve any operator to 'dereference' the reference, so it doesn't matter that the reference declarator symbol clashes with the address-of operator. The same symbol means completely different things in the two contexts, and there is never a need to use one meaning in the context where the other is allowed.
So char &foo(int &a) declares a function taking a reference to an int and returning a reference to a char. func(&x) is an expression taking the address of x and passing it to func.
1. In fact in the original C syntax for declaring functions 'declarations follow use' was even more strictly followed. For example you'd declare a function as int foo(a,b) and the types of parameters were declared elsewhere, so that the declaration would look exactly like a use, without the extra typenames.
2. Of course int *&x; could make sense in that *&x could be an int, but C doesn't actually do that.
What you're asking about are called pointers (*), and reference to (&), which I think is best explained here.
The symbols & and * are used to denote a reference and pointer type, respectively.
int means simply the type 'int',
int* means 'pointer to int',
int& means 'reference to int',
A pointer is a variable which is used to store the address of a variable.
A reference has the syntax of its base type, but the semantics of a pointer to that type. This means you don't need to dereference it in order to change the value.
To take an example, the following code blocks two are semantically equivalent:
int* a = &value;
*a = 0;
And:
int& a = value;
a = 0;
The main reasons to use pointers or references as an argument type is to avoid copying of objects and to be able to change the value of a passed argument. Both of these work because, when you pass by reference, only the address is copied, giving you access to the same memory location as was "passed" to the function.
In contrast, if a reference or pointer type is not used, a full copy of the argument will be made, and it is this copy which is available inside the function.
The symbols * and & have three meanings each in C++:
When applied to an expression, they mean "dereference" and "address-of" respectively, as you know.
When part of a type, they mean "pointer" and "reference", respectively.
Since C++ doesn't care about arbitrary spacing, the declaration int *ptr is exactly the same as the declaration int* ptr, in which you can now more clearly see that this is an object called ptr of type int*.1
When used between two expressions, they mean "multiply" and "bitwise AND", respectively.
1 - though, frustratingly, this isn't actually how the internal grammar reads it, thanks to the nasty legacy of C's type system. So avoid single-line multi-declarations involving pointers unless you want a surprise.
Ex: What is the difference between 'void func(int *var)' and 'void
func(int **var)'? What about 'int &var'?
The same question stands for return types, as well as arguments. What
does 'int& func(int var)' mean, as compared to 'int* func(int var)'?
And in arguments, how does 'y = func(*x)' differ from 'y = func(&x)'?
(1)
<return type> <function name> <parameters>
void func (int *var)
<parameter> here int *var is a pointer to integer, ie it can point to
an array or any buffer that should be handled with integer pointer
arithmetic. In simple terms , var holds the address of the respective
**actual parameter.**
eg: int arr[10];
func(arr);
int a = 33;
func(&a);
Here, &a means we are explicitly passing address of the the variable 'a'.
(2)
int m = 0;
int &var = m;
Here var means reference, ie it another alias name for variable 'm' ,
so any change 'var' makes will change the contents of variable 'm'.
var = 2; /* will change the actual contents of 'm' */
This simple example will not make sense , unless you understand the context.
Reference are usually use to pass parameter to function, so that changes made by
the function to the passed variable is visible at the caller.
int swap(int &m, int &n) {
tmp = m;
m = n;
n = tmp;
}
void main( void ) {
int x = 1, y = 2;
swap(x, y);
/* x = 2, y =1 */
}
(3)
'int& func(int var)' mean, as compared to 'int* func(int var)'?
int& func(int var) means the function returns a reference;
int* func(int var) means the function returns a pointer / address;
Both of the them has its context;
int& setNext() {
return next;
}
setNext() = previous;
where as
int* setNext() {
return &next;
}
int *inptr;
inptr = setNext();
*inptr = previous;
In the previous two lines,
int *inptr <- integer pointer declaration;
*inptr <- means we are accessing contents of the address pointed by inptr;
ie we are actually referring to 'next' variable.
The actual use is context specific. It can't be generalized.
(4)
how does 'y = func(*x)' differ from 'y = func(&x)'?
y = func(&x) is already explained.
y = func(*x) , well i'm not sure if you actually meant *x.
int swap(int *m, int *n) {
tmp = *m;
*m = *n;
*n = tmp;
}