0% found this document useful (0 votes)
27 views

C++ 2024H1 Assignment-11

This document contains 7 multiple choice questions about C++ programming. The questions cover topics like universal references, rvalue references, overloaded constructors, template classes, lambda functions and more.

Uploaded by

sreeramvrkumar
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
27 views

C++ 2024H1 Assignment-11

This document contains 7 multiple choice questions about C++ programming. The questions cover topics like universal references, rvalue references, overloaded constructors, template classes, lambda functions and more.

Uploaded by

sreeramvrkumar
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 17

Programming in Modern C++: Assignment Week 11

Total Marks : 25

Partha Pratim Das


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

March 27, 2024

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

template <typename T>


class CData {
public:
Data(Data&& obj); //LINE-1
void f1(T&& v); //LINE-2
template <class U>
void f2(U&& v); //LINE-3
template<class V>
void f3(std::vector<V>&& v); //LINE-4
//some more code
private:
T val_;
};

From among the following identify the line(s) which use(s) parameter passing with a universal
reference.

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: c)
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, therefore && at LINE-1 is just a rvalue reference,
not a universal reference.
At LINE-2, no type deduction takes place since the type deduction for T took place at the
time of class instantiation. Therefore && at LINE-2 is just a rvalue reference, not a universal
reference.
At LINE-3, the template type parameter U requires type deduction. Thus, && at LINE-3

1
indicates a universal 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.
&& indicates a universal reference only where template type deduction takes place. However,
if no type deduction takes place, then it is just rvalue reference, not universal reference. Thus,
b) is the correct option.
Intentionally made as MSQ

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

#include <iostream>

class base1 {
public:
base1(const int& n) { std::cout << "base1 - lvalue : " << n << ", "; }
base1(int&& n) { std::cout << "base1 - rvalue : " << n << ", "; }
};

class base2 {
public:
base2(const int& n) { std::cout << "base2 - lvalue : " << n << ", "; }
base2(int&& n) { std::cout << "base2 - rvalue : " << n << ", "; }
};

class derived : public base1, public base2{


public:
template<typename T1, typename T2>
derived(T1&& n1, T2&& n2) : _________________________ { } //LINE-1
};
int main(){
int i = 10;
derived b1(i, std::move(i));
return 0;
}

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

a) base1(n1), base2(n2)

b) base1(n1), base2(std::forward<T2>(n2))

c) base1(std::forward<T1>(n1)), base2(n2)

d) base1(std::forward<T1>(n1)), base2(std::forward<T2>(n2))

Answer: b), d)
Explanation:
From the output, we can understand that for class base1 the l-value version of the constructors
and for class base2 the r-value version of the constructors need to be called. Since at the
constructor of class derived, n1 and n2 are received as universal reference types, n1 can be
forwarded to class base1 constructor as base(n1) or as base(std::forward<T>(n1)), but n2
needs to be forwarded to class base2 constructor as base2(std::forward<T>(n2)).

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

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


enum class CCARD {GOLD, SILVER, TITANIUM, PLATINUM};
enum {GOLD, SILVER, TITANIUM, PLATINUM};

bool check1(METAL type){


return type == METAL::GOLD ? true : false; //LINE-1
}

bool check2(METAL type){


return type == CCARD::SILVER ? true : false; //LINE-2
}

bool check3(METAL type){


type == TITANIUM ? true : false; //LINE-3
}

Identify the statement/s which are true for the above code segment.

a) It generates compilation error at LINE-1

b) It generates compilation error at LINE-2

c) It generates compilation error at LINE-3

d) There is no error in the given code segment

Answer: b), c)
Explanation:
At LINE-1, the statement type == METAL::GOLD compares between two METAL type elements,
which compiles successfully.
At LINE-2, the statement type == CCARD::SILVER compares between METAL type with CCARD
type, which are not type castable. Thus, it generates error.
At LINE-3, the statement type == TITANIUM compares between METAL type with int, which
are not type castable. Thus, it generates error.

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

#include <iostream>

template<typename T>
class ttype{
public:
ttype() = default;
ttype(T val) : val_(val){ }
ttype(const ttype& ) = default;
ttype& operator=(const ttype& ) = delete;
ttype(ttype&& ) = default;
ttype& operator=(ttype&& ) = delete;
private:
T val_;
};
int main(){
ttype<char> d1(’A’);
ttype<char> d2(d1); //LINE-1
ttype<char> d3;
d3 = d1; //LINE-2
ttype<char> d4 = std::move(d1); //LINE-3
ttype<char> d5;
d5 = std::move(d1); //LINE-4
return 0;
}

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

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: b), d)
Explanation:
Since assignment operator overload and move assignment operator overload are deleted, LINE-2
and LINE-4 both generates error.

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

#include <iostream>

class customer{
public:
explicit customer() : customer(0) { } //LINE-1
explicit customer(const int ID) : customer(ID, defaultBalance) { } //LINE-2
explicit customer(const double balance) : customer(0, balance) { } //LINE-3
explicit customer(const int ID, const double balance)
: ID_{ID}, balance_{balance} { } //LINE-4
friend std::ostream& operator<<(std::ostream& os, const customer& st);
private:
int ID_ ;
double balance_ ;
static constexpr double defaultBalance = 1000.0;
};

std::ostream& operator<<(std::ostream& os, const customer& c){


os << "[" << c.ID_ << ", " << c.balance_ << "]" << ", ";
return os;
}

int main(){
customer c1;
customer c2(1011);
customer c3(2000.0); //LINE-5
customer c4(1012, 3000.0); //LINE-6
std::cout << c1 << c2 << c3 << c4;
return 0;
}

What will be the output/error?

a) [0, 0], [1011, 0], [2000, 0], [1012, 3000],

b) [0, 1000], [1011, 1000], [0, 2000], [1012, 3000],

c) compiler error at LINE-5: ambiguous call c3(2000.0)

d) compiler error at LINE-6: ambiguous call c4(1012, 3000.0)

Answer: b)
Expanation:
The statement at LINE-5 call the default constructor at LINE1, which delegates the call to the
parameterized constructor at LINE-2, which further delegates the call to the parameterized
constructor at LINE-4.

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

#include <iostream>
#include <string>

class person {
public:
person(){}
explicit person(int ID) : ID_{ID} { }
protected:
int ID_ {0}; //LINE-1
std::string name_ {"unknown"}; //LINE-2
};

class customer: public person {


public:
explicit customer(double balance) : balance_{balance} { }
using person::person;
void print(){
std::cout << "[" << ID_ << ", " << name_ << ", " << balance_ << "]";
}
protected:
double balance_ {0.0}; //LINE-3
};

int main(){
customer c1(1011); //LINE-4
customer c2(30000.0); //LINE-5
c1.print();
c2.print();
return 0;
}

What will be the output/error?

a) [0, unknown, 1011][0, unknown, 30000]

b) [1011, unknown, 0][0, unknown, 30000]

c) Compiler error at LINE-1, LINE-2 and LINE-3: C++ does not allow in-class
initialization for the data members

d) Compiler error at LINE-4 and LINE-5: ambiguous calls

Answer: b)
Explanation:
The statement using person::person; in class customer allows customer to inherit the
default constructor from class person. Thus, the statement customer c1(1011); calls the
constructor from personinitializes the data member ID . Whereas, the statement customer
c2(30000.0); calls the constructor from class customer and initializes balance . Further-
more, C++11 allows in-class initialization so no error at LINE-1, LINE-2 and LINE-3. Thus,
b) is the correct option.

7
Question 7
Consider the code segment (C++14) given below. [MCQ, Marks 2]

#include <iostream>

template<typename T> T pi = T(22L)/7;


int main(){
pi<int> = 5;
//area of circle = pi * r * r
auto area1 = [](auto(r)) { return pi<decltype(r)> * r * r; }(10);
auto area2 = [](auto(r)) { return pi<double> * r * r; }(10);
auto area3 = [](auto(r)) { return pi<decltype(r)> * r * r; }(10.0);
auto area4 = [](auto(r)) { return pi<int> * r * r; }(10);
std::cout << area1 << ", " << area2 << ", " << area3 << ", " << area4;
return 0;
}

What will be the output?

a) 300, 314.286, 314.286, 300

b) 500, 314.286, 314.286, 500

c) 300, 314.286, 314.286, 500

d) 314.286, 314.286, 314.286, 500

Answer: b)
Explanation:
In the expression: [](auto(r)) { return pi<decltype(r)> * r * r; (10)}, the inferred
type of r is int. So, area1 = 500.
In the expression: [](auto(r)) { return pi<double> * r * r; }(10) , the pi<double>
is double(22L)/3. So, area2 = 314.286.
In the expression: [](auto(r)) { return pi<decltype(r)> * r * r; }(10.0) , the in-
ferred type of r is double. So, area3 = 314.286.
In the expression: [](auto(r)) { return pi<int> * r * r; }(10) , the pi<int> is 5. So,
the result is area4 = 500.

8
Question 8
Consider the code segment (C++11) given below. [MCQ, Marks 2]
#include <iostream>
#include <list>

int main(){
std::list<int> li {10, 20, 30, 40};
double sum = 0.0;
//start code-segment
auto add = [li, &sum](int d) {
double res = 0.0;
for(auto i : li){
sum += i;
res += (double)i/d;
}
return res;
};
//end code-segment
double r = add(5);
std::cout << sum << ", " << r;
return 0;
}
Identify the appropriate functor class implementation in place of the marked code segment(Portion
of the code marked by start and end) from the given options, such that the output of the pro-
gram remains the same that is the output is 100, 20.
a) struct add_closure {
std::list<int>& val_d;
double ref_d;
add_closure(std::list<int>& li, double sum) : val_d(li), ref_d(sum) { }
double operator()(int param) {
double res = 0.0;
for(auto i : val_d){
ref_d += i;
res += (double)i/param;
}
return res;
};
};
auto add = add_closure(li, sum);

b) struct add_closure {
std::list<int> val_d;
double ref_d;
add_closure(std::list<int> li, double& sum) : val_d(li), ref_d(sum) { }
double operator()(int param) {
double res = 0.0;
for(auto i : val_d){
ref_d += i;
res += (double)i/param;
}

9
return res;
};
};
auto add = add_closure(li, sum);

c) struct add_closure {
std::list<int> val_d;
double& ref_d;
add_closure(std::list<int> li, double& sum) : val_d(li), ref_d(sum) { }
double operator()(int param) const {
double res = 0.0;
for(auto i : val_d){
ref_d += i;
res += (double)i/param;
}
return res;
};
};
auto add = add_closure(li, sum);

d) struct add_closure {
std::list<int> val_d;
double& ref_d;
add_closure(std::list<int> li, double& sum) : val_d(li), ref_d(sum) { }
operator()(int param) const {
double res = 0.0;
for(auto i : val_d){
ref_d += i;
res += (double)i/param;
}
return res;
};
};
auto add = add_closure(li, sum);

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

• data members:

– a value member each for each value capture


– a reference member each for each reference capture

• 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 <vector>

int main(){
int p = 1, s = 0;
std::vector<int> vec {1, 2, 3, 4};
______________________________________ { //LINE-1
for(auto& i : vec){
i *= m;
sum += i;
}
};
int sum = 0;
evalute(10, sum);
for(auto i : vec)
std::cout << i << ", ";
std::cout << sum;
return 0;
}

Identify the appropriate option(s) to fill in the blanks at LINE-1 such that the output becomes
10, 20, 30, 40, 100.

a) auto evalute = [](int m, int& sum)

b) auto evalute = [&vec](int m, int& sum)

c) auto evalute = [=](int m, int& sum)

d) auto evalute = [&](int m, int& sum)

Answer: b), d)
Explanation:
Since the variable vec is modified within the lambda function, it needs to be captured by
reference. Therefore, both options b) and d) are correct.

11
Programming Questions

Question 1
Consider the following program that implements a recursive lambda function to find out the
nm , where n, m ≥ 1.

• Fill in the blank at LINE-1 to declare the signature of recPow as std::function.

• Fill the blank at LINE-2 to complete the definition of lambda function recPow.

• Fill the blank at LINE-3 to complete the definition of lambda expression print, which
calls recPow.

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

#include <iostream>
#include <functional>

int main(){
___________________________________; //LINE-1
recPow = ______________________________ { //LINE-2
return m == 1 ? n : n * recPow(n, m - 1);
};
auto print = ______________________ { //LINE-3
std::cout << recPow(n, m);
};
int n, m;
std::cin >> n >> m;
print(n, m);
return 0;
}

Public 1
Input: 2 5
Output: 32

Public 2
Input: 4 3
Output: 64

Private
Input: 10 3
Output: 1000

Answer:
LINE-1: std::function<int(int, int)> recPow
LINE-2: [&recPow](int n, int m) -> int
LINE-3: [&recPow](int n, int m)
Explanation:
At LINE-1, we can use std::function to declare the signature of RecMin as:
std::function<int(std::vector<int>, int)> RecMin

12
At LINE-2 to complete the definition of lambda function RecMin is as follows:

recPow = [&recPow](int n, int m) -> int { //LINE-2


return m == 1 ? n : n * recPow(n, m - 1);
};

At LINE-3 to complete the definition of lambda expression print is as follows:

auto print = [&recPow](int n, int m) {


std::cout << recPow(n, m);
};

13
Question 2
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 getmin function.

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

#include <iostream>

___________________________________ //LINE-1
double getmin(________){ return num; } //LINE-2

___________________________________ //LINE-3
double getmin(_____________________){ //LINE-4
return num <= getmin(nums...) ? num : getmin(nums...); //LINE-4
}

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

Public 1
Input:
3 1 5
3.4 5.7 1.2 8.9
Output: 1 1.2 1

Public 2
Input:
4 3 2
9.8 1.2 3.4 .9
Output: 2 0.9 0.9

Private
Input:
7 0 9
1 0.0 2.3 8.1
Output: 0 0 0

Answer:
LINE-1: template <typename T>
or

14
LINE-1: template <class T>
LINE-2: T num
LINE-3: template <typename T, typename... Tail>
or
LINE-3: template <class T, class... 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

15
Question 3
Consider the program below (in C++11).

• Fill in the blank at LINE-1 with appropriate template declaration.

• Fill in the blank at LINE-2 with an appropriate parameter for function makePayment.

• Fill in the blank at LINE-3 to complete the return statement.

The program must satisfy the given test cases. Marks: 3

#include <iostream>
class payment{
public:
virtual void pay() = 0;
};

class upi_payment : public payment {


public:
upi_payment(const int& upi_num) : upi_num_{upi_num}{
std::cout << "lvalue" << " ";
}
upi_payment(int&& upi_num) : upi_num_{upi_num}{
std::cout << "rvalue" << " ";
}
void pay(){ std::cout << upi_num_ << " "; }
private:
int upi_num_;
};

class bank_transfer : public payment {


public:
bank_transfer(const int& acc_no) : acc_no_(acc_no){
std::cout << "lvalue" << " ";
}
bank_transfer(int&& acc_no) : acc_no_(acc_no){
std::cout << "rvalue" << " ";
}
void pay(){ std::cout << acc_no_ << " "; }
private:
int acc_no_;
};

____________________________________ //LINE-1
T1 makePayment(________){ //LINE-2
return ___________________________; //LINE-3
}
int main() {
int a, b;
std::cin >> a >> b;

auto p1 = makePayment<upi_payment>(a);
auto p2 = makePayment<upi_payment>(std::move(a));

16
auto p3 = makePayment<bank_transfer>(b);
auto p4 = makePayment<bank_transfer>(std::move(b));
std::cout << std::endl;
p1.pay();
p2.pay();
p3.pay();
p4.pay();
return 0;
}

Public 1
Input: 10 20
Output:
lvalue rvalue lvalue rvalue
10 10 20 20

Public 2
Input: 5 3
Output:
lvalue rvalue lvalue rvalue
5 5 3 3

Private
Input: 1 2
Output:
lvalue rvalue lvalue rvalue
1 1 2 2

Answer:
LINE-1: template<typename T1, typename T2>
or
LINE-1: template<class T1, class T2>
LINE-2: T2&& val
LINE-3: T1(std::forward<T2>(val))
Explanation:
This code is a typical example of factory method. Since the function return type and the
parameters both are template parameter type, at LINE-1 the template must be declared as:
template<typename T1, typename T2>
or
template<class T1, class T2>
The parameter for makePayment must be universal reference type which can be declared as:
LINE-2: T2&& valm
Depending on the instantiation of parameter type T1 the function makePayment return an
object of upi payment or bank transfer type, which can be done as:
T1(std::forward<T2>(val))

17

You might also like