Rvalues cannot be used to initialize lvalue (normal) references. But if I write a helper conversion function, it works. What is going on in the background and is it possibly dangerous?
template <class T>
inline T& getLvalueRef(T&& x)
{
return x;
}
The compiler accepts this.
And then
int ten = 10;
int& ref = getLvalueRef(ten+8);
// use some variables to rewrite memory
int a = 7;
int b = 10;
int c = (a+b)*6;
// check if still works
cout << ref << endl; // okay, still 18
ref = 9;
cout << ref << endl; // okay, 9
Your code invokes undefined behaviour. ten+8 creates a temporary, whose lifetime ends at the end of the full-expression in which it appears (in your case, the semicolon). getLvalueRef then returns a reference to this temporary.
Any usage of this reference past the full-expression in which ten+8 was created is not allowed.
Related
I have defined a constexpr function as following:
constexpr int foo(int i)
{
return i*2;
}
And this is what in the main function:
int main()
{
int i = 2;
cout << foo(i) << endl;
int arr[foo(i)];
for (int j = 0; j < foo(i); j++)
arr[j] = j;
for (int j = 0; j < foo(i); j++)
cout << arr[j] << " ";
cout << endl;
return 0;
}
The program was compiled under OS X 10.8 with command clang++. I was surprised that the compiler did not produce any error message about foo(i) not being a constant expression, and the compiled program actually worked fine. Why?
The definition of constexpr functions in C++ is such that the function is guaranteed to be able to produce a constant expression when called such that only constant expressions are used in the evaluation. Whether the evaluation happens during compile-time or at run-time if the result isn't use in a constexpr isn't specified, though (see also this answer). When passing non-constant expressions to a constexpr you may not get a constant expression.
Your above code should, however, not compile because i is not a constant expression which is clearly used by foo() to produce a result and it is then used as an array dimension. It seems clang implements C-style variable length arrays as it produces the following warning for me:
warning: variable length arrays are a C99 feature [-Wvla-extension]
A better test to see if something is, indeed, a constant expression is to use it to initialize the value of a constexpr, e.g.:
constexpr int j = foo(i);
I used the code at the top (with "using namespace std;" added in) and had no errors when compiling using "g++ -std=c++11 code.cc" (see below for a references that qualifies this code) Here is the code and output:
#include <iostream>
using namespace std;
constexpr int foo(int i)
{
return i*2;
}
int main()
{
int i = 2;
cout << foo(i) << endl;
int arr[foo(i)];
for (int j = 0; j < foo(i); j++)
arr[j] = j;
for (int j = 0; j < foo(i); j++)
cout << arr[j] << " ";
cout << endl;
return 0;
}
output:
4
0 1 2 3
Now consider reference https://msdn.microsoft.com/en-us/library/dn956974.aspx It states: "...A constexpr function is one whose return value can be computed at compile when consuming code requires it. A constexpr function must accept and return only literal types. When its arguments are constexpr values, and consuming code requires the return value at compile time, for example to initialize a constexpr variable or provide a non-type template argument, it produces a compile-time constant. When called with non-constexpr arguments, or when its value is not required at compile-time, it produces a value at run time like a regular function. (This dual behavior saves you from having to write constexpr and non-constexpr versions of the same function.)"
It gives as valid example:
constexpr float exp(float x, int n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp(x * x, n / 2) :
exp(x * x, (n - 1) / 2) * x;
}
This is an old question, but it's the first result on a google search for the VS error message "constexpr function return is non-constant". And while it doesn't help my situation, I thought I'd put my two cents in...
While Dietmar gives a good explanation of constexpr, and although the error should be caught straight away (as it is with the -pedantic flag) - this code looks like its suffering from some compiler optimization.
The value i is being set to 2, and for the duration of the program i never changes. The compiler probably noticed this and optimized the variable to be a constant (just replacing all references to variable i to the constant 2... before applying that parameter to the function), thus creating a constexpr call to foo().
I bet if you looked at the disassembly you'd see that calls to foo(i) were replaced with the constant value 4 - since that is the only possible return value for a call to this function during execution of the program.
Using the -pedantic flag forces the compiler to analyze the program from the strictest point of view (probably done before any optimizations) and thus catches the error.
I am now studying C++ 11 and getting confused by value category of expressions in C++ 11. According to terminology the Lvalue is the top-left point of the W, that is iM (or i-m sometimes) meaning that "has identity but cannot be moved from". This really makes me confused. Please consider the example below:
#include <iostream>
int main()
{
int a = 0, b = 1, c = 2;
a = std::move(b = c);
std::cout << a << '\n';
}
This example compiled well.
We all know that the assignment b = c is an Lvalue then what do they mean by 'cannot be moved from'? Please give examples that can clearly illustrate this!
Thanks!
Roughly speaking:
an lvalue has identity because you can take its address
int x;
&x; // ok
an lvalue cannot be moved from because it cannot be used as an argument to move constructor/assignment
struct Foo
{
Foo(Foo&); // 0
Foo(Foo&&); // 1
};
Foo x;
Foo y{x}; // calls 0, not 1
in the example above, x is an lvalue: the copy constructor is invoked. If you want to move from x, you need to make it an rvalue: this is why you must use std::move(x) to cast it to an rvalue reference.
Foo y{std::move(x)}; // calls 1
In your example std::move(b = c) is an rvalue, as std::move is literally just a static_cast to an rvalue reference.
maybe I get something wrong with shared_pointers or there is some basic shortcoming of mine but I couldn't get this right. So I want to read in some data from a file. There are position and momentum data on each line of the data file and the first line stores the number of data points.
I need to read this in to my data structure and for some reason my graph would not fill, although the data reads in correctly.
const int dim = 3; // dimension of problem
template <typename T, typename G>
// T is the type of the inputted locations and G is the type of the
// distance between them
// for example: int point with float/double distance
struct Node{
std::pair< std::array<T, dim>,std::pair< std::array<T, dim>, G > > pos; // position
std::pair< std::array<T, dim>,std::pair< std::array<T, dim>, G > > mom; // momentum
// a pair indexed by a position in space and has a pair of position
// and the distance between these points
};
template <typename T, typename G>
struct Graph{
int numOfNodes;
std::vector< Node<T,G> > nodes;
};
This is the data structure and here's my read function (std::cout-s are only for testing):
template <typename T, typename G>
std::istream& operator>>(std::istream& is, std::shared_ptr< Graph<T,G> >& graph){
is >> graph->numOfNodes; // there's the number of nodes on the first line of the data file
std::cout << graph->numOfNodes << "\n";
for(int k=0; k<graph->numOfNodes; k++){
Node<T,G> temp;
for(auto i : temp.pos.first){
is >> i;
std::cout << i << "\t";
}
std::cout << "\t";
for(auto i : temp.mom.first){
is >> i;
std::cout << i << "\t";
}
std::cout << "\n";
graph->nodes.push_back(temp);
}
return is;
}
I have an output function as well. So if I output the graph which I intended to fill during read-in is zeroed out. Number of nodes os correct however positions and momente are all zeroed out. What did I do wrong? Thanks in advance.
for(auto i : temp.pos.first){
is >> i;
std::cout << i << "\t";
}
Think of this as similar to a function. If you have something like:
void doX(int i) { i = 42; }
int main() {
int j=5;
doX(j);
return j;
}
Running this code, you'll see the program returns the value 5. This is because the function doX takes i by value; it basically takes a copy of the variable.
If you replace doX's signature with
void doX(int &i)
and run the code, you'll see it returns 42. This is because the function is now taking the argument by reference, and so can modify it.
Your loops will behave similarly. As you have it now, they take a copy of the values in the arrays in turn, but are not by reference.
As with the function, you can change your loops to look like
for(auto &i : temp.pos.first){
is >> i;
std::cout << i << "\t";
}
This should then let you change the values stored in the arrays.
I want to redefine the bit shift operator on a 64 bit unsigned integer in c++ in such a way that I can do say, x<<d, where x is a 64 bit integer and d is an integer with |d|<64, to make it equivalent to x<<d for d>0 and x>>|d| for d<0.
The only way I know how to do this is to define a whole new class and overload the << operator, but I think that also means I need to overload all the other operators I need (unless there is a trick I don't know), which seems a bit silly considering I want them to behave exactly as they do for the pre-defined type. It's just the bitshift that I want to change. At present, I have just written a function called 'shift' to do this, which doesn't seem very c++ ish, even though it works fine.
What is the stylistically correct way to do what I need?
Thanks
If you were able to do this, it would be very confusing to other C++ programmers who read your code and see:
int64 x = 92134;
int64 y = x >> 3;
And have it behave differently than their expectations, and behave differently from what the C++ standard defines.
The stylistic choice that agrees most with the C++ code I've seen is to continue using your own myshift() function.
int64 y = myshift(x, 3);
I think it's very horrible (and I propose it just for fun) but... if you accept to wrap the number of bit shifted in a struct...
#include <iostream>
struct foo
{ int num; };
long long int operator<< (const long long int & lli, const foo & f)
{
int d { f.num };
if ( d < 0 )
d = -d;
if ( d >= 64 )
d = 0;
return lli << d;
}
int main()
{
long long int lli { 1 };
std::cout << (lli << foo{+3}) << std::endl; // shift +3
std::cout << (lli << foo{-3}) << std::endl; // shift +3 (-3 -> +3)
std::cout << (lli << foo{+90}) << std::endl; // no shift (over 64)
std::cout << (lli << foo{-90}) << std::endl; // no shift (over 64)
return 0;
}
// struct representing every edge in the graph
template<class Type>
struct Vertex
{
Type info;
list<vertexConnection<Type> >adjacents;
};
This is how I try to print it but I am getting errors
for(int i=0; i <count; i++)
{
typename list<vertexConnectivity<Type> >::iterator j;
list<vertexConnection<Type> > s = node[i].adjacents;
for(j = s.begin(); j != s.end(); ++j)
{
cout << *j;
}
}
How do I print the content in the list adjacents that is of type vertexConnection which on the other hand is of type Type.
The errors I am getting are:
at the line with cout << *j;
graph.h:313:2: error: no match for ‘operator<<’ in ‘std::cout << j.std::_List_iterator<_Tp>::operator* with _Tp = GraphNameSpace::vertexConnectivity, std::_List_iterator<_Tp>::reference = GraphNameSpace::vertexConnectivity&’
line is ostream& operator <<(ostream&, Country&);
country.h:24:10: note: std::ostream& operator<<(std::ostream&, Country&)
country.h:24:10: note: no known conversion for argument 2 from ‘GraphNameSpace::vertexConnectivity’ to ‘Country&’
Thanks
*j is a vertexConnection<Type> but you never provided any instructions to your compiler on how to represent that as text. You want to stream it to std::cout: okay, but how? According to what rules and logic?
You'll need to write a stringise function and call it, or overload operator<< for that type:
template <typename T>
std::ostream& operator<<(std::ostream& s, const vertexConnection<T>&);
At the moment your compiler is pointing out that you did at least provide one for Country objects, but that it can't be used in this case.
Two things.
Use range-based for loop (C++11 feature) to simplify element visit.
Please see http://herbsutter.com/elements-of-modern-c-style/
Provide overloaded operator<< for each of your user defined types.
For example,
std::ostream& operator<<(std::ostream& s, const Country& c);