03 Mar 2018
At times we need to check cpu support for a particular feature, for example: We may need to check in our code if the CPU my code is running on supports AVX or not. To check this we can use compiler Intrinstics. One such intrinsic for gcc/clang (I am not sure if other compilers support this) is __builtin_cpu_supports
. This instrinsic returns true if the hardware supports the feature given as input the the function call. Assume I want to check if my hardware supports AVX or not, I can check it as below:
#include<stdio.h>
int main(){
if(__builtin_cpu_supports("avx"))
printf("AVX supported\n");
else
printf("AVX not supported\n");
return 0;
}
By the way, you can check check list of all the flags supported by your cpu in the file cpuinfo under proc file system too.
mayank:~> cat /proc/cpuinfo|grep -i flags
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss ht syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts nopl xtopology tsc_reliable nonstop_tsc cpuid pni pclmulqdq ssse3 cx16 pcid sse4_1 sse4_2 x2apic popcnt aes xsave avx f16c rdrand hypervisor lahf_lm cpuid_fault pti fsgsbase smep arat
20 Aug 2017
References Series:
- References in C++
20 Aug 2017
Starting from this post we will talk about lvalue references, pointers, rvalue references, move semantics etc.
This is first post in this series. You will find all the post of this series here.
This post will talk just about references (lvalue references to be precise). But if you don’t understand how lvalue references differ from rvalue references don’t worry we will try to understand all these jargons in this series.
What is meant by references?
A reference
defines an alternative name for an object. A reference type ‘refers to’ another type. Reference is like an alias for another variable.
Defining a reference
int a = 10;
int &refA = a;
In above snippet we bound a reference refA
to integer variable a
. In other words, refA
is alias for a
.
Few important points to remember
- A reference is not an object. Reference, is just another name for an object.
- It is necessary to initialize references.
- There’s no way to rebind references. Once bound a reference remains bound to its initial object.
- All the operations on a reference are actually on object to which reference is bound.
- With few expections the type of reference should match the type of object to which reference is bound.
- As references are not objects so we can’t define reference to a reference.
Let’s try to understand all above points in detail.
A reference is not an object. Reference, is just another name for an object.
Not much to say here. Just don’t think of references as object.
It is necessary to initialize references.
Initializing a reference is necessary.
int a = 10;
int &refA; // Error
int &refA;
is illegal, as we have not initialized the reference named refA
.
There’s no way to rebind references. Once bound a reference remains bound to its initial object.
References reamins bounded to the object which it was initialized with, through out the life of reference.
From Point 2 and 3 we can conclude that references can’t be bound to NULL as intialization of references is necessary and also we can’t rebind them. So there’s no way of binding reference to NULL.
Let’s consider below example to understand why reference re-binding is ambigous.
int a = 10;
int b = 20;
int &refA = a;
refA = b;
Now assume that we allowed references to rebound. In this case refA = b
in above code snippet can mean one of below two:
- Rebound reference
refA
to b.
- Change the value of object pointed by
refA
, which is a
to 20.
So it would be quite ambigous if rebinding references would have been allowed. So in C++ statement refA = b
would mean that value of a
is change to 20.
All the operations on a reference are actually on object to which reference is bound.
#include<iostream>
int main(){
int a =10;
int b = 20;
int &refA = a;
int &refB = b;
std::cout << refA + refB ; //Ouput : 30
}
Adding refA
and refB
actually performs operation on a
and b
. When we assign to a reference, we are assigning to the object to which the reference is bound. When we fetch the value of a reference, we are really fetching the value of the object to which the reference is bound. Similarly, when we use a reference as an initializer, we are really using the object to which the reference is bound.
With few expections the type of reference should match the type of object to which reference is bound.
float a =10;
int &refA = a;
We define a
of type float, but we are trying to bind this object to reference of type int. This is not allowed.
NOTE: We will talk about exception which is mentioned here in later post.
As references are not objects so we can’t define reference to a reference.
Just as we define pointers to pointers we can’t define references to references.
This was about basics of reference. We will continue this series in next blog post.
Till then Sayonara.
Thanks.
06 Aug 2017
This post is in continuation to Lambdas in C++.
Till now we covered basics of functors and lambdas in C++. We will cover Mutable lambdas in this post.
Mutable Lambdas
Object captured in lambda are immutable by default. This is because operator()
of the generated functor (compiler generates functional object for lambdas) is const
by default. Consider below C++ code:
#include<iostream>
int main(){
int a=10;
auto lam = [a](){a;};
lam();
return 0;
}
Assembly code for lambda lam
generated by gcc 4.9.4 is:
main::{lambda()#1}::operator()() const:
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
pop rbp
ret
As you can see that const
keyword is present in generated functor of lambda main::{lambda()#1}::operator()() const
. This const
prevent us from modifying objects in lambda captured by value.
int a=10;
auto lam = [a](){a++;}; //Compilation error
Using mutable
keyword allows us to mutate objects captured by value too.
int a=10;
auto lam = [a]() mutable {a++;};
If we see the assembly code for same code the generated functor after adding mutable keyword looks like:
main::{lambda()#1}::operator()()
We can clearly see that const
is no longer present now. So adding mutable
keyword makes operator()
non-const
.
In general lambda declaration mutable
keyword comes before return-type
auto func = [a]() mutable -> int {++a; std::cout << a; return a;};
That’s it for mutable lambdas. I think we covered basics of lambdas. We will start with R-value reference from next blog post.
Till then Sayonara.
23 Jul 2017
Lambdas vs Functors
As we saw in last post we can use STL functors for common operations like sum, divide. But at times when we need to write our own functor the amount of code needed to define functor is too much. Below is an example to show how useful and concise lambdas can be.
Using functors :
#include<iostream>
#include<vector>
#include<algorithm>
using myPair = std::pair<int,int>;
struct MyCompare{
bool operator()(myPair p1,myPair p2){
return p2.second > p1.second;
}
}mycompare;
int main(){
std::vector<myPair> records(3);
records[0] = std::make_pair(12,10);
records[1] = std::make_pair(2,19);
records[2] = std::make_pair(1,12);
std::sort(records.begin(),records.end(),mycompare);
}
Using lambdas ( >C++11 ):
#include<iostream>
#include<vector>
#include<algorithm>
int main(){
using myPair = std::pair<int,int>;
std::vector<myPair> records(3);
records[0] = std::make_pair(12,10);
records[1] = std::make_pair(2,19);
records[2] = std::make_pair(1,12);
std::sort(records.begin(),records.end(),
[](myPair p1,myPair p2){return p2.second > p1.second;});
}
What is a lambda?
A lambda is syntactic sugar for writing functors. Lambda can be thought of as unnamed inline function. Like any another C++ function lambdas has parameters, return type and body. Unlike a function, lambdas may be defined inside a function.
Syntax
In general, A lambda expression looks like:
[ capture list ] ( parameter list ) -> return type { function body }
Now let’s try to understand what each entity in above definition means.
[ capture list ]
By default, variables of the enclosing scope cannot be accessed by a lambda.
int a = 10;
auto myLambda = [](){std::cout << a ;}; // ERROR
myLambda();
In above code snippet we are trying to use value of a without capturing, hence error.
The capture list specifies which outside variables are available for the lambda function and whether they should be captured by value or by reference. Capturing a variable makes it accessible inside the lambda.
Capture a
by value: [a](){}
Capture a
by reference: [&a](){}
When an variable is captured by value we cannot change value of the variable inside lambda.
/*
a is captured by value and we are changing
value of a, which is not allowed. So this is
an error.
*/
auto myLambda = [a](){a = a+2;} // ERROR
If we want to change value of variable in lambda we need to capture a by reference (by having & before variable name in capture list). In this case change in value of a inside lambda would be reflected outside lambda too.
int a = 10;
/*
To change value of a in lambda we need
to capture by reference, as in below statement.
*/
auto myLambda2 = [&a](){a = a+2;} // Works!
myLambda2();
print(a); // Value of a becomes 12 outside
// scope of lambda2.
Few points to remember :
-
Even if there isn’t any variables to capture, having []
is mandatory. We can keep capture list
empty like []
when we don’t want to capture anything.
-
Don’t confuse capture list
with arguments of conventional functions. Unlike function arguments, they do not have to be passed when calling the lambda.
capture list
captures the value of variable when lambda was defined and not at time when lambda was called.
int a =10;
auto myLambda = [a](){std:::cout << a;};
a =14;
myLambda(); // myLambda get value of a as 10 and not 14.
- Variable should be defined in scope of lambda.
auto myLambda = [a](){a = a+2;} // Error: a is not defined.
int a =10;
myLambda();
( Parameter list )
This is the optional parameters list. We can omit parentheses when we don’t need any argument to lambda (except in case when lambda is defined as mutable, we will see this later).
auto myLambda = [] { std::cout « ” Hello world”; };
// Valid. Notice we don’t have () of parameter list between
capture list and function body.
return type
This is the return type of lambda. Most of the time, compilers can deduce the return type of the lambda expression when you have zero or one return statement, returning same type.
auto myLambda = [](){std::cout << "hi";};
// return type is deduced as void
auto myLambda2 = [](){ if(a==2) return 2; else return 3;};
// return type would be deduced as int
However, in case when multiple return types are of different type compiler won’t be able to deduce the return type and will thrown error.
auto myLambda3 = [](){ if(a==2) return 2; else return 3.5;}; // ERROR
// Compiler won't be able to deduce return type of lambda
// and hence compiler would throw error. We will need to
// specify return type in this case.
auto myLambda4 = []()-> double { if(a==2) return 2; else return 3.5;};
// Works as return type is specified.
This post talks about syntax and some basic rules of lambdas. In next post we will talk about some more concepts in lambdas like mutable lambdas, recursive lambdas etc.
Till then, Sayonara.
Thanks,
Mayank