C++ 2024H1 Assignment-11
C++ 2024H1 Assignment-11
Total Marks : 25
Question 1
Consider the code segment (in C++11) given below. [MSQ, Marks 2]
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 << ", "; }
};
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]
Identify the statement/s which are true for the above 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;
}
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;
};
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;
}
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
};
int main(){
customer c1(1011); //LINE-4
customer c2(30000.0); //LINE-5
c1.print();
c2.print();
return 0;
}
c) Compiler error at LINE-1, LINE-2 and LINE-3: C++ does not allow in-class
initialization for the data members
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>
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 public inline const function call operator() with the parameters of the lambda as
parameters, generated from the body of the lambda
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.
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 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:
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-2 with an appropriate parameter for function makePayment.
#include <iostream>
class payment{
public:
virtual void pay() = 0;
};
____________________________________ //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