0% found this document useful (0 votes)
11 views18 pages

Assignment 11 Solution

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views18 pages

Assignment 11 Solution

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 18

Programming in Modern C++: Assignment Week 11

Total Marks : 27

Partha Pratim Das


Department of Computer Science and Engineering
Indian Institute of Technology Kharagpur, Kharagpur – 721302
[email protected]

March 29, 2023

Question 1
Consider the program (in C++11) given below. [MSQ, Marks 2]

#include <iostream>

class A {
public:
A(const int& n) { std::cout << "base - lvalue : " << n << std::endl; }
A(int&& n) { std::cout << "base - rvalue : " << n << std::endl; }
};

class B {
public:
template<typename T, typename U>
B(T&& n1, U&& n2) : ____________________ { } //LINE-1
private:
A a1_, a2_;
};
int main(){
int i = 10;
B b1(i, 20);
return 0;
}

Choose the appropriate option to fill in the blank at LINE-1 so that the output becomes
base - lvalue : 10
base - rvalue : 20

a) LINE-1: a1 (n1), a2 (n2)

b) LINE-1: a1 (std::forward<T>(n1)), a2 (std::forward<U>(n2))

c) LINE-1: a1 (n1), a2 (std::forward<U>(n2))

d) LINE-1: a1 (std::forward<T>(n1)), a2 (n2)

Answer: b), c)
Explanation:

1
From the output we can understand that for object a1 the l-value version of the constructors
and for object a2 the r-value version of the constructors need to be called. Since at the con-
structor of class B, n1 and n2 are received as universal reference types, n1 can be forwarded to
class A constructor as a1 (n1) or as a1 (std::forward<T>(n1)) but n1 needs to be forwarded
to class A constructor as a1 (std::forward<T>(n2))

2
Question 2
Consider the code segment (in C++11) given below. [MSQ, Marks 2]

template<typename T>
class TestData{
public:
void fun1(T&& n); //LINE-1
template<typename U>
void fun2(U&& n); //LINE-2
void fun3(TestData&& n); //LINE-3
template<typename V>
void fun4(std::vector<V>&& n); //LINE-4
};

Identify the line/s where && indicates a universal reference.

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: b)
Explanation:
Note that && usually indicates rvalue reference. && indicates a universal reference only where
type deduction takes place.
At LINE-1, no type deduction takes place during function call (the type deduction takes place
during class instantiation), therefore && at LINE-1 is just a rvalue reference, not a universal
reference.
At LINE-2, the template type parameter U requires type deduction. Thus, && at LINE-2
indicates a universal reference.
At LINE-3, requires no type deduction. Thus, && at LINE-3 indicates a rvalue reference.
At LINE-4, the template type parameter V requires type deduction. However, since the form of
function parameter is not V&& (it in form std::vector<V>&&), it indicates only rvalue reference.
Intentionally kept as MSQ

3
Question 3
Consider the following code segment (in C++11). [MSQ, Marks 2]

#include <iostream>

enum class CCType {SILVER, GOLD, PLATINUM};


enum class METAL {SILVER, GOLD, PLATINUM};
enum MEMBERSHIP {SILVER, GOLD, PLATINUM};

bool isSilver(CCType col){


if(col == CCType::SILVER) //LINE-1
return true;
return false;
}

bool isGold(CCType col){


if(col == METAL::GREEN) //LINE-2
return true;
return false;
}

bool isPlatinum(CCType col){


if(col == PLATINUM) //LINE-3
return true;
return false;
}

int main() {
if(isPlatinum(CCType::PLATINUM) && isGold(CCType::GOLD) && isSilver(CCType::SILVER))
std::cout << "true";
return 0;
}

Identify the statement/s which are true for the given program.

a) It generates compiler error at LINE-1

b) It generates compiler error at LINE-2

c) It generates compiler error at LINE-3

d) It generates the output true

Answer: b), c)
Explanation:
The statement if(col == CCType::SILVER) compares between two CCType type elements,
which compiles successfully.
The statement if(col == METAL::GREEN) compares between CCType type with METAL type,
which are not type castable. Thus it generates error.
The statement if(col == PLATINUM) compares between CCType type with int, which are not
type castable. Thus it generates error.
Since the code generates compiler error, it will not produce any output.

4
Question 4
Consider the following code segment (in C++11). [MCQ, Marks 2]

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
std::vector<int> iVec {20, 40, 60, 10, 50};
/* code-block-1 */
sort(iVec.begin(), iVec.end(), compare());
for(int i : iVec)
std::cout << i << " ";
return 0;
}

Identify the appropriate code block to be placed at code-block-1 such that the output is 60
50 40 20 10 .

a) bool compare(int a, int b){ return a > b; }

b) struct compare{
bool operator()(int a, int b){ return a > b; }
};

c) class compare{
bool operator()(int a, int b){ return a > b; }
};

d) bool operator()(int a, int b){ return a > b; }

Answer: b)
Explanation:
A functor can be local to a function; however, it is not possible for a function or class. Therefore,
b) is the correct option.

5
Question 5
Consider the following code segment (in C++11). [MSQ, Marks 2]

#include <iostream>
template<typename T>
class Data{
public:
Data() = delete;
Data(T _i) : i(_i){ }
Data(const Data& ) = delete;
Data(Data&& ) = default;
private:
T i;
};
int main(){
Data<int> d1; //LINE-1
Data<int> d2(30); //LINE-2
Data<int> d3 = d2; //LINE-3
Data<int> d4 = std::move(d2); //LINE-4
return 0;
}

Which of the following line/s generate/s compiler error/s?

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: a), c)
Explanation:
Since the default constructor and the copy constructor of class Data are explicitly deleted.
LINE-1 and LINE-3m generate compiler errors.

6
Question 6
Consider the following code segment (in C++11). [MCQ, Marks 2]

#include <iostream>

class emp{
public:
explicit emp() : emp(0) { std::cout << "#1 "; } //LINE-1
explicit emp(const int i) : emp(i, dSalary) { std::cout << "#2 "; } //LINE-2
explicit emp(const double s) : emp(0, s) { std::cout << "#3 "; } //LINE-3
emp(int i, double s) : id_{i}, salary_{s} { std::cout << "#4 ";} //LINE-4
private:
int id_ { -1 };
double salary_ { 0.0 };
static constexpr double dSalary = 10000.00;
};

int main(){
emp e1;
return 0;
}

What will be the output?

a) #1

b) #2 #1

c) #4 #2 #1

d) #1 #2 #4

Answer: c)
Explanation:
The instatiation of object as emp e1; causes the follwoing consecutive calls to the constrcutors:

1. constructor at LINE-1,

2. constructor at LINE-2,

3. constructor at LINE-4.

Since the constructors are executed in reverse order of the calls, the output would be #4 #2
#1 .

7
Question 7
Consider the following program (in C++14). [MCQ, Marks 2]

#include <iostream>

template<typename T> T cvrt = T(2.54);


int main(){
cvrt<int> = 100;
auto cm_2_m = [](auto(cm)) { return cm * cvrt<decltype(cm)>; }(100);
auto cm_2_in = [](auto(cm)) { return cm * cvrt<decltype(cm)>; }(100.0);
std::cout << cm_2_m << ", " << cm_2_in;
return 0;
}

What will be the output?

a) 254, 254

b) 10000, 10000

c) 10000, 254

d) 254, 10000

Answer: c)
Explanation:
In the expression: [](auto(cm)) return cm * cvrt<decltype(cm)>; (100) , the inferred
type of cm is int. So, the result is 10000.
In the expression: [](auto(cm)) return cm * cvrt<decltype(cm)>; (100.0) , the in-
ferred type of cm is double. So, the result is 254.

8
Question 8
Consider the following λ expression (in C++11). [MCQ, Marks 2]

auto stat = [d, &sum](std::list<int> l) {


for(auto i : l)
sum += i;
return (double)sum / l.size();
};

Identify the most appropriate option that define the equivalent closure object for the above
lambda function.

a) struct stat_closure {
int d;
int& sum;
stat_closure(int d_, int& sum_) : d(d_), sum(sum_) { }
void operator()(std::list<int> l, double& avg) const {
for(auto i : l)
sum += i;
avg = (double)sum / l.size();
}
};
auto stat = stat_closure(d, sum);

b) struct stat_closure {
int d;
int sum;
stat_closure(int d_, int& sum_) : d(d_), sum(sum_) { }
operator()(std::list<int> l) {
for(auto i : l)
sum += i;
return (double)sum / l.size();
}
};
auto stat = stat_closure(d, sum);

c) struct stat_closure {
int d;
int sum;
stat_closure(int d_, int& sum_) : d(d_), sum(sum_) { }
double operator()(std::list<int> l) const {
for(auto i : l)
sum += i;
return (double)sum / l.size();
}
};
auto stat = stat_closure(d, sum);

d) struct stat_closure {
int d;
int& sum;
stat_closure(int d_, int& sum_) : d(d_), sum(sum_) { }
double operator()(std::list<int> l) const {

9
for(auto i : l)
sum += i;
return (double)sum / l.size();
}
};
auto stat = stat_closure(d, sum);

Answer: d)
Explanation:
For a λ-expression, the compiler creates a functor class with:

• data members:

– a value member each for each value capture (interval)


– a reference member each for each reference capture (result)

• a constructor with the captured variables as parameters

– a value parameter each for each value capture


– a reference parameter each for each reference capture

• a public inline const function call operator() with the parameters of the lambda as
parameters, generated from the body of the lambda

• copy constructor, copy assignment operator, and destructor

10
Question 9
Consider the following code segment (in C++11). [MSQ, Marks 2]

#include <iostream>
#include <string>

class intData {
public:
intData(bool data) : d1_(data) { }
intData(std::string data) : d2_(data) { }

explicit operator bool const() {


if(d2_ == "")
return d1_ == false ? 0 : 1;
else
return d2_ == "true" ? 1 : d2_ == "false" ? 0 : -1;
}

private:
bool d1_ { false };
std::string d2_ { "" };
};

int main(){
std::string v = "false";
intData i1(true);
intData i2(v);
std::cout << i1 << " "; //LINE-1
std::cout << (bool)i2 << " "; //LINE-2
std::cout << static_cast<bool>(i1) << " "; //LINE-3
std::cout << bool(i2) << " "; //LINE-4
return 0;
}

Which of the following lines will generate compiler error/s?

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: a)
Explanation:
Since the typecast (to bool) operator is overloaded at LINE-1 is explicit, the typecast to bool
must an explicit typecasting. LINE-1 has an implicit which causes compiler error. The rest of
the options are explicit typecasting.
Intentionally kept as MSQ

11
Programming Questions

Question 1
Consider the following program (in C++11).
• Fill in the blanks at LINE-1 and LINE-3 with appropriate template definitions.

• Fill in the blanks at LINE-2 and LINE-4 with appropriate parameters for findMax func-
tion.
The program must satisfy the sample input and output. Marks: 3
#include <iostream>

_____________________ //LINE-1
double findMax(__________________){ return num; } //LINE-2

_____________________ //LINE-3
double findMax(__________________){
return num >= findMax(nums...) ? num : findMax(nums...); //LINE-4
}

int main(){
int a, b, c;
double d, e, f;
std::cin >> a >> b >> c;
std::cin >> d >> e >> f;
std::cout << findMax(a, b, c) << " ";
std::cout << findMax(d, e, f) << " ";
std::cout << findMax(a, b, c, d, e, f);
return 0;
}

Public 1
Input:
10 20 30
12.5 15.5 20.5
Output:
30 20.5 30

Public 2
Input:
1 5 3
2.3 6.7 2.1
Output:
5 6.7 6.7

Private
Input:
400 30 100
10.65 100.56 200.43

12
Output:
400 200.43 400

Answer:
LINE-1: template <typename T>
LINE-2: T num
LINE-3: template <typename T, typename... Tail>
LINE-4: T num, Tail... nums
Explanation:
At LINE-1, the definition of the simple template is:
template <typename T>
, and at LINE-3 the parameter of the function findMax are:
T num
At LINE-3, the definition of the veriadic template is:
template <typename T, typename... Tail>
, and at LINE-4 the parameters of the function findMax are:
T num, Tail... nums

13
Question 2
Consider the following program (in C++11). Fill in the blanks as per the instructions given
below:

• Fill in the blank at LINE-1 with an appropriate template declaration for the function
wrapper.

• Fill in the blank at LINE-2 with an appropriate header for function wrapper.

• Fill in the blank at LINE-3 with an appropriate return statement for function wrapper.

The program must satisfy the sample input and output. Marks: 3

#include <iostream>
#include <vector>

template<typename T, typename U>


struct Summation{
double operator()(std::ostream& os, std::vector<T>&& v1, std::vector<U>&& v2){
os << "rvalue version: ";
double sum {0.0};
for(T i : v1) sum += i;
for(U i : v2) sum += i;
return sum;
}
//template<typename T, typename U>
double operator()(std::ostream& os, const std::vector<T>& v1,
const std::vector<U>& v2){
os << "lvalue version: ";
double sum {0.0};
for(T i : v1) sum += i;
for(U i : v2) sum += i;
return sum;
}
};

____________________________________________ //LINE-1
__________________________________________ { //LINE-2
_______________________________________; //LINE-3
}

int main() {
std::vector<int> iv;
std::vector<double> dv;
for(int i = 0; i < 3; i++){
int a;
std::cin >> a;
iv.push_back(a);
}
for(int i = 0; i < 3; i++){
double b;
std::cin >> b;
dv.push_back(b);

14
}

std::cout << wrapper(std::cout, Summation<int, double>(), iv, dv);


std::cout << std::endl;
std::cout << wrapper(std::cout, Summation<int, double>(), std::move(iv),
std::move(dv));
return 0;
}

Public 1
Input:
10 20 30
1.5 2.5 2.5
Output:
lvalue version: 66.5
rvalue version: 66.5

Public 2
Input:
1 -3 -4
2.5 4.5 -3
Output:
lvalue version: -2
rvalue version: -2

Private
Input:
43 12 6
10.5 3.6 -98.3
Output:
lvalue version: -23.2
rvalue version: -23.2

Answer:
LINE-1: template<typename F, typename... T>
Or
LINE-1: template<class F, class... T>
LINE-2: auto wrapper(std::ostream& os, F&& func, T&&... args) -> decltype(func(os,
args...)) in C++11.
Or
LINE-2: decltype(auto) wrapper(std::ostream& os, F&& func, T&&... args) in C++14.
LINE-3: return func(os, std::forward<T>(args)...)
Explanation:
At LINE-1 the template for function wrapper can be declared as:
template<typename F, typename... T>
Or
template<class F, class... T>
At LINE-2 header for function wrapper can be written as:
auto wrapper(std::ostream& os, F&& func, T&&... args) -> decltype(func(os, args...))
in C++11.

15
Or
decltype(auto) wrapper(std::ostream& os, F&& func, T&&... args) in C++14.
At LINE-3 the return statement should be:
return func(os, std::forward<T>(args)...)

16
Question 3
Consider the following program (in C++11) to find factorials of 3 integers. Fill in the blanks
as per the instructions given below:

• Fill in the blank at LINE-1 to complete the λ function for computing factorial.

• Fill in the blank at LINE-2 to complete the λ function for printing the vector v2.

The program must satisfy the sample input and output. Marks: 3

#include <iostream>
#include <functional>
#include <vector>

int main() {
std::vector<int> v1;
std::vector<long long> v2;

for(int i = 0; i < 3; i++){


int a;
std::cin >> a;
v1.push_back(a);
}

_________________________________________________ { //LINE-1
return n > 1 ? n * fact(n - 1) : 1;
};

for(auto i : v1)
v2.push_back(fact(i));

_________________________________________________ { //LINE-2
for (auto i : x){ std::cout << i << " "; } }(v2);

return 0;
}

Public 1
Input: 2 3 4
Output: 2 6 24

Public 2
Input: 1 3 5
Output: 1 6 120

Private
Input: 2 4 6
Output: 2 24 720

Answer:
LINE-1: const std::function<long long(int)> fact = [&fact](int n)

17
LINE-2: [](std::vector<long long> x)
Explanation:
The λ function for computing the factorial can be written as:

const std::function<long long(int)> fact = [&fact](int n) {


return n > 1 ? n * fact(n - 1) : 1;
};

The λ function for printing the vector v2 can e written as:

[](std::vector<long long> x) { for (auto i : x){ std::cout << i << " "; } }(v2);

18

You might also like