Ranged for loop with literal list? - c++

In C++11, is it possible to write the following
int ns[] = { 1, 5, 6, 2, 9 };
for (int n : ns) {
...
}
as something like this
for (int n : { 1, 5, 6, 2, 9 }) { // VC++11 rejects this form
...
}

tl;dr: Upgrade your compiler for great success.
Yeah, it's valid.
The definition of ranged-for in [C++11: 6.5.4/1] gives us two variants of syntax for this construct. One takes an expression on the right-hand-side of the :, and the other takes a braced-init-list.
Your braced-init-list deduces (through auto) to a std::initializer_list, which is handy because these things may be iterated over.
[..] for a range-based for statement of the form
for ( for-range-declaration : braced-init-list ) statement
let range-init be equivalent to the braced-init-list. In each case, a range-based for statement is equivalent to
{
auto && __range = range-init;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
[..]
So, you are basically saying:
auto ns = { 1, 5, 6, 2, 9 };
for (int n : ns) {
// ...
}
(I haven't bothered with the universal reference here.)
which in turn is more-or-less equivalent to:
std::initializer_list<int> ns = { 1, 5, 6, 2, 9 };
for (int n : ns) {
// ...
}
Now, GCC 4.8 supports this but, since "Visual Studio 11" is in fact Visual Studio 2012, you'll need to upgrade in order to catch up: initialiser lists were not supported at all until Visual Studio 2013.

It is possible to use this construction with an initializer list. Simply it seems the MS VC++ you are using does not support it.
Here is an example
#include <iostream>
#include <initializer_list>
int main()
{
for (int n : { 1, 5, 6, 2, 9 }) std::cout << n << ' ';
std::cout << std::endl;
return 0;
}
You have to include header <initializer_list> because the initializer list in the for statement is converted to std::initializer_list<int>

Related

How to remove the Nth element in a range?

I can write:
my_range | ranges::views::remove(3)
using the ranges-v3 library, to remove the element(s) equal to 3 from the range my_range. This can also be done in C++20 with
my_range | std::views::filter([](auto const& val){ return val != 3; })
But - how can I remove the element at position 3 in my_range, keeping the elements at positions 0, 1, 2, 4, 5 etc.?
Here's one way to do it:
#include <iostream>
#include <ranges>
#include <range/v3/view/take.hpp>
#include <range/v3/view/drop.hpp>
#include <range/v3/view/concat.hpp>
int main() {
const auto my_range = { 10, 20, 30, 40, 50, 60, 70 };
auto index_to_drop = 3; // so drop the 40
auto earlier = my_range | ranges::views::take(index_to_drop - 1);
auto later = my_range | ranges::views::drop(index_to_drop);
auto both = ranges::views::concat(earlier, later);
for (auto const & num : both) { std::cout << num << ' '; }
}
This will produce:
10 20 30 50 60 70
... without the 40.
See it working on Godbolt. Compilation time is extremely poor though. Also, concat() is not part of C++20. Maybe in C++23?
The most straightforward way I can think of in range-v3 would be:
auto remove_at_index(size_t idx) {
namespace rv = ranges::views;
return rv::enumerate
| rv::filter([=](auto&& pair){ return pair.first != idx; })
| rv::values;
}
To be used like:
my_range | remove_at_index(3);
enumerate (and its more general cousin zip) is not in C++20, but will hopefully be in C++23.

"bisection method" run infinity times [duplicate]

So I came across this question somewhere:
Case 1:
int a;
a = 1, 2, 3;
printf("%d", a);
Case 2:
int a = 1, 2, 3;
printf("%d", a);
The explanation says:
The second case gives error because comma is used as a separator, In first case = takes precedence over , so it is basically (a=1), 2, 3;
But I want to ask why does = not take precedence over , in Case 2?
It is not just a question of precedence, but rather a question of the language grammar: the = in both cases is not the same operator:
in the declaration int a = 1, 2, 3;, the = token introduces an initializer which cannot be a comma expression. The , ends the initializer and the compiler issues an error because 2 is not a valid identifier for another variable.
in the statement a = 1, 2, 3;, a = 1, 2, 3 is an expression, parsed as ((a = 1), 2), 3 because = has higher precedence than ,. = is the assignment operator whose right hand side is an expression, this assignment is the left operand of a comma operator , followed by a constant expression 2, a = 1, 2 itself the left operand of the final , operator whose right operand is 3. The statement is equivalent to ((a = 1), 2), 3);, which simplifies into a = 1;.
This
int a = 1, 2, 3;/* not a valid one */
is wrong because since = has higher priority, so it become int a = 1 internally and there is no name for 2 and 3 thats why this statement is not valid and cause compile time error.
To avoid this you might want to use
int a = (1, 2, 3); /* evaluate all expression inside () from L->R and assign right most expression to a i.e a=3*/
And here
int a;
a = 1,2,3;
there are two operator = and , and see man operator. The assignment operator = has higher priority than comma operator. So it becomes a=1.
a = 1,2,3;
| L--->R(coma operator associativity)
this got assigned to a
for e.g
int x = 10, y = 20,z;
z = 100,200,y=30,0; /* solve all expression form L to R, but finally it becomes z=100*/
printf("x = %d y = %d z = %d\n",x,y,z);/* x = 10, y = 30(not 20) z = 100 */
z = (100,200,y=30,0); /* solve all expression form L to R, but assign right most expression value to z*/
Inside variable declarations (as case 1) comma are used to declare several variables, for example:
int a,b=2,c=b+1,d; //here only b and c were initialized
An statement in C/C++ could be a list of comma separated expressions (this is what happens in case 2):
a=b+1, c+=2, b++, d = a+b+c, 3, d; //these are expressions, remember one literal is an expression too!!!
NOTE : comma (,) is a compile time operator,
from my side their is Four cases that you can come across :
case 1
int a = 1, 2, 3; // invalid case cause too many initializers
case 2
int a = (1, 2, 3); // valid case
/* You can expand this line as a :
1;
2;
int a = 3;
*/
case 3
int a;
a = 1, 2, 3; // valid case
/* You can expand this line as a :
a = 1; // expression 1
2; // expression 2
3; // expression 3
*/
case 4
int a;
a = ( 1, 2, 3);// valid case
/* You can expand this line as a :
1; // expression 1
2; // expression 2
a = 3; // expression 3
*/
In above cases in place of 1, 2, 3 we can use any valid expression in C, explore more!!

How do Range-Based for loops handle temporary containers [duplicate]

This question already has an answer here:
Does a C++11 range-based for loop condition get evaluated every cycle?
(1 answer)
Closed 8 years ago.
Assume this example:
vector<int> get_vector();
for(auto& v: get_vector())
{
...
}
Is get_vector() re-evaluated on each iteration? Or a temporary is stored and evaluated once?
get_vector() is evaluated once, and the result is stored in a temporary.
6.5.4/1 ...a range-based for statement is equivalent to
{
auto && __range = range-init;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
In your example, range-init would be (get_vector()).

Accepting random number of inputs cpp [duplicate]

This question already has answers here:
Variable number of arguments in C++?
(17 answers)
Closed 8 years ago.
I want to accept some inputs for a program,the inputs are integer values.
The condition on accepting the inputs is number of inputs is not fixed
but maximum number of inputs to be taken is fixed.
for example lets say the maximum input limit is 15 inputs.
So I should be able to accept "n" inputs where "n" can have any value from 1 to 15.
Is there a way to do this in cpp?
There is a general mechanism in C and C++ for writing functions that accept an arbitrary number of arguments. Variable number of arguments in C++?. However, this will not create a restriction on the number of args or restrict the overloads to a fixed type and it is generally a bit clunky to use (IMO).
It is possible to do something with variadic templates, for instance:
#include <iostream>
#include <vector>
using namespace std;
void vfoo(const std::vector<int> &ints)
{
// Do something with the ints...
for (auto i : ints) cout << i << " ";
cout << endl;
}
template <typename...Ints>
void foo(Ints...args)
{
constexpr size_t sz = sizeof...(args);
static_assert(sz <= 15, "foo(ints...) only support up to 15 arguments"); // This is the only limit on the number of args.
vector<int> v = {args...};
vfoo(v);
}
int main() {
foo(1);
foo(1, 2, 99);
foo(1, 4, 99, 2, 5, -33, 0, 4, 23, 3, 44, 999, -43, 44, 3);
// foo(1, 4, 99, 2, 5, -33, 0, 4, 23, 3, 44, 999, -43, 44, 3, 0); // This will not compile
// You can also call the non-template version with a parameter pack directly:
vfoo({4, 3, 9});
// Downside is that errors will not be great; i.e. .this
// foo(1.0, 3, 99);
// /Users/jcrotinger/Work/CLionProjects/so_variadic_int_function/main.cpp:21:22: error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]
// vector<int> v = {args...};
// ^~~~
// /Users/jcrotinger/Work/CLionProjects/so_variadic_int_function/main.cpp:38:5: note: in instantiation of function template specialization 'foo<double, int, int>' requested here
// foo(1.0, 3, 99);
// ^
return 0;
}
The static assert is the only thing that will limit this to 15 arguments. As the comment indicates, type checking is messy since the error message will come not from the function call but from the initialization of the vector.
This does require support for C++ 11's variadic templates.

question about ? and : in c++

Why this statement :
int a = 7, b = 8, c = 0;
c = b>a?a>b?a++:b++:a++?b++:a--;
cout << c;
is not equal to :
int a = 7, b = 8, c = 0;
c = (b>a?(a>b?a++:b++):a++)?b++:a--;
cout << c;
and is equal to :
int a = 7, b = 8, c = 0;
c = b>a?(a>b?a++:b++):(a++?b++:a--);
cout << c;
Please give me some reason. Why ?
Because ? : is right-to-left associative. It's defined like that in the language.
I believe #sth has provided the correct answer, however, I think #Skilldrick got it right on the comments - why the hell would you ever write something like that.
As well as the precedence issue, you really need to be careful when incrementing the same variables in a single statement. There may or may not be sequence points in the statement, and therefore the order of evaluation of the increments might not be guaranteed. You could end up with different results with different compilers or even different optimization settings on the same compiler.
The operators &&, ||, and ?: perform flow control within expressions. ?: behaves like an if-else statement.
c = b>a?a>b?a++:b++:a++?b++:a--;
if ( b>a )
if ( a>b )
a ++;
else
b ++;
else if ( a ++ )
b ++;
else
a --;
b>a? (
a>b ?
a ++
:
b ++
) : ( a ++ ?
b ++
:
a --
)
The associativity is necessary to have behavior like if … else if … else.
Sometimes I use an expression similar to yours for lexicographic sequence comparision:
operator< ()( arr &l, arr &r ) {
return l[0] < r[0]? true
: r[0] < l[0]? false
: l[1] < r[1]? true
: r[1] < l[1]? false
: l[2] < r[2];
}