0% found this document useful (0 votes)
41 views16 pages

C++ 2024H1 Assignment-10

The document contains 8 multiple choice questions about C++ programming concepts. The questions cover topics like template deduction, constexpr objects, copy/move constructors, and function overloading. Correct answers and explanations are provided for each question.

Uploaded by

sreeramvrkumar
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)
41 views16 pages

C++ 2024H1 Assignment-10

The document contains 8 multiple choice questions about C++ programming concepts. The questions cover topics like template deduction, constexpr objects, copy/move constructors, and function overloading. Correct answers and explanations are provided for each question.

Uploaded by

sreeramvrkumar
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/ 16

Programming in Modern C++: Assignment Week 10

Total Marks : 25

Partha Pratim Das


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

March 20, 2024

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

#include<iostream>
int main( ){
int n = 10;
int& rn = n;
______ tn = rn; //LINE-1

++tn;
std::cout << n << " " << rn << " " << tn;
return 0;
}

Identify the appropriate option/s to fill in the blank at LINE-1 such that output becomes
10 10 11

a) auto

b) auto&

c) decltype(rn)

d) decltype((n))

Answer: a)
Explanation:
Since auto never deduces adornments like cv-qualifer or reference, in option a) the inferred
type of tn is int. Thus, output will be 10 10 11.
In option b) the inferred type of tn is int&. Thus, output will be 11 11 11.
In option c) the inferred type of tn is the type of rn that is int&. Thus, output will be 11 11
11.
In option d) the inferred type of t is the type of reference to n that is int&. Thus, output will
be 11 11 11.
Intentionally kept as MSQ

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

#include <iostream>

int main( ){
int arr[] = { 1, 2, 3, 4, 5 };
for(________________ : arr) // LINE-1
i *= 2;

for(int i = 0; i < 5; i++)


std::cout << arr[i] << " ";
return 0;
}

Identify the appropriate option(s) to fill in the blank at LINE-1 such that the output of the
program is NOT: 2 4 6 8 10

a) auto i

b) auto& i

c) decltype(*arr) i

d) decltype(arr[0]) i

Answer: a)
Explanation:
In option a), the inferred type of i is int. Thus, the changes made in i are not reflected in
the array arr. So, the O/P is 1 2 3 4 5
In option b), the inferred type of i is int&. Thus, the changes made in i are reflected in the
array arr.
In option c), the inferred type of i is the output of decltype(*arr) i.e. int&. Thus, the
changes made in i are reflected in the array arr. In option d), the inferred type of i is the
output of decltype(arr[0]) i.e. int&. Thus, the changes made in i are reflected in the array
arr.
Intentionally kept as MSQ.

2
Question 3
Consider the following code segment. [MSQ, Marks 2]

#include <iostream>

class data{
public:
constexpr data(int n = 0) : n_{n} { }
private:
int n_;
};

const int num_gen1(){


return 1;
}

constexpr int num_gen2(const int i){


return i + 10;
}

int main(){
int i = 10;
const int j = 20;
constexpr data d1(1); //LINE-1
constexpr data d2(i); //LINE-2
constexpr data d3(num_gen1()); //LINE-3
constexpr data d4(num_gen2(j)); //LINE-4
return 0;
}

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

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: b), c)
Explanation:
At LINE-1, the constructor parameter is constant from the compile time context. Thus, the
object can be constexpr.
At LINE-2, the constructor parameter is non-const. Thus, the object can not be of constexpr.
At LINE-3, the constructor parameter is the return value of the num gen1() function. However,
the return type of num gen1() is not constexpr, therefore the object cannot be constexpr.
At LINE-4, the constructor parameter is the return value of the num gen2(int) function.
However, the return type of it is constexpr, therefore the object can be constexpr.

3
Question 4
Consider the program (in C++11) given below. [MSQ, Marks 2]
#include <iostream>
constexpr double pi = 3.14;

namespace v1_0 {
class circle{
public:
circle(int r) : r_(r) {}
double area(){ return pi * r_ * r_; }
private:
int r_;
};
}

inline namespace v2_0 {


template<typename T>
class circle{
public:
circle(T r) : r_(r) {}
double area(){ return pi * r_ * r_; }
private:
T r_;
};
}

int main(){
____________ c1(10.5); //LINE-1
____________ c2(10.5); //LINE-2
____________ c3(10.5); //LINE-3
std::cout << c1.area() << " " << c2.area() << " " << c3.area();
return 0;
}
Choose the appropriate option to fill in the blanks at LINE-1, LINE-2, and LINE-3 so that the
program runs without any compilation error and produces the output:
314 314 346.185
a) LINE-1: circle
LINE-2: circle<int>
LINE-3: circle<double>

b) LINE-1: v1 0::circle
LINE-2: v2 0::circle<int>
LINE-3: circle<double>

c) LINE-1: v1 0::circle
LINE-2: circle<int>
LINE-3: circle<double>

d) LINE-1: v2 0::circle
LINE-2: v2 0::circle<int>
LINE-3: v2 0::circle<double>

4
Answer: b), c)
Explanation:
Since namespace v2 0 is declared as inline and it defines the templated version of class circle,
the templated class circle can be instantiated with or without namespace resolution. How-
ever, for namespace v1 0 (defines the non-templated version of circle), namespace resolution
is not mandated.

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

#include<iostream>
#include<iomanip>
constexpr double cr = 12.0;

long double operator"" _FT(long double l) {


return l;
}
long double operator"" _IN(long double l) {
return cr * l;
}
class length{
public:
length(double l1 = 0, double l2 = 0) : l1_(l1), l2_(l2){}
int operator()(){ return l1_ + l2_; }
private:
int l1_, l2_;
};
int main() {
length len(______, _______); //LINE-1
std::cout << len() << "IN";
return 0;
}

Choose the appropriate option to fill in the blank at LINE-1 such that the output is 125IN.

a) 5.0FT, 10.0IN

b) (FT)5, (IN)10

c) 5.0 FT, 10.0 IN

d) 5 FT, 11 IN

Answer: c)
Explanation:
For user-defined numeric literal operators, the correct way to invoke them is to write them as
5.0 FT, 10.0 IN.
All other options are compilation error. Even option d) is wrong as numeric literal operators
require exact type matching.
Intentionally kept as MSQ

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

#include<iostream>
class A{
public:
A(const int& n) { std::cout << "#1 " ; }
A(const A& ob) { std::cout << "#2 " ; }
A(A&& ob) noexcept { std::cout << "#3 " ; }
};

class B : public A {
public:
B(const int& n, const int& m) : A(n) { std::cout << "#4 " ; }
B(const B& ob) : A(ob) { std::cout << "#5 " ; }
B(B&& ob) noexcept : A(ob) { std::cout << "#6 " ; }
};

int main(){
B b1(1, 2);
B b2(b1);
B b3 = std::move(b1);
return 0;
}

What will be the output?

a) #1 #4 #2 #5 #3 #6

b) #1 #4 #2 #5 #2 #6

c) #1 #4 #2 #5 #3 #5

d) #1 #4 #2 #6 #2 #6

Answer: b)
Explanation:
The statement b1(100, 200) invokes the parameterized constructor of B class, which forwards
the call to the parameterized constructor of A class. It prints #1 #4.
The statement B b2(b1) invokes the copy constructor of B class, which forwards the call to
the copy constructor of A class. It prints #2 #5.
The statement B b3 = std::move(b1); invokes the move constructor of B class, which (how-
ever) forwards the call to the copy constructor of A class. It prints #2 #6.

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

#include <iostream>
#include <initializer_list>

template<typename T>
class items{
public:
items() { std::cout << "cont-1 "; }
items(char c) { std::cout << "cont-2 "; }
items(std::initializer_list<T> elms) { std::cout << "cont-3 "; }
items(char c, std::initializer_list<T> elms) { std::cout << "cont-4 "; }
};
int main(){
items<char> c1(’a’);
items<char> c2({’a’, ’b’, ’c’});
items<char> c3{’a’, ’b’, ’c’};
items<char> c4 = {’a’, ’b’, ’c’};
items<char> c5(’d’, {’a’, ’b’, ’c’});
return 0;
}

What will be the output?

a) cont-3 cont-3 cont-3 cont-3 cont-3

b) cont-2 cont-2 cont-3 cont-2 cont-4

c) cont-2 cont-3 cont-3 cont-3 cont-4

d) cont-2 cont-2 cont-3 cont-3 cont-3

Answer: c)
Explanation:
c1(’a’) invokes parameterized constructor items(char c) { ... }.
c2({’a’, ’b’, ’c’)}, c3{’a’, ’b’, ’c’} and c4 = {’a’, ’b’, ’c’} invoke the initializer
list constructor items(std::initializer list<T> elms){ ... }.
c5(’d’, {’a’, ’b’, ’c’}) invokes the mixed constructor
items(char c, std::initializer list<T> elms){ ... }.

8
Question 8
Consider the following code segment. [MSQ, Marks 2]

#include <iostream>

void print(char* str){ /*some code*/ }

template<typename Fun, typename Param>


void caller(Fun func, Param p){
func(p);
}

int main(){
char s[2] = "0";
caller(print, s); //LINE-1
caller(print, 0); //LINE-2
caller(print, s[1]); //LINE-3
caller(print, nullptr); //LINE-4
return 0;
}

Which of the following lines generate/s compiler error?

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: b), c)
Explanation:
For the call in LINE-1, the template type parameter Param is deduced to char*. Thus, it does
not generate any compiler error.
For the call in LINE-2, the template type parameter Param is deduced to int. Thus, it gener-
ates a compiler error.
For the call in LINE-3, the template type parameter Param is deduced to char. Thus, it gen-
erates a compiler error.
For the call in LINE-4, the template type parameter Param is deduced to std::nullptr t and
the call print(std::nullptr t) is syntactically correct.

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

#include<iostream>
struct double_it{
int n_;
double_it(int n) : n_(2 * n){}
int operator()() { std::cout << "lval "; return n_; }
};

struct triple_it{
int n_;
triple_it(int n) : n_(3 * n){}
int& operator()() { std::cout << "rval "; return n_; }
};

template < typename T >


_______________________________________ { //LINE-1
return op() ;
}

int main(){
double_it o1{10};
triple_it o2{10};
std::cout << wrapper(o1) << " ";
std::cout << (wrapper(o2) = 20);
return 0;
}

Identify the appropriate option/s to fill in the blank at LINE-1 such that output becomes
lval 20 rval 20.

a) decltype(op()) wrapper( T& op )

b) auto wrapper( T& op ) -> decltype(op())

c) auto wrapper( T& op )

d) decltype(auto) wrapper( T& op )

Answer: b), d)
Explanation:
The call wrapper(o1) evaluates to prvalue of type int.
The call wrapper(o2) = 20 evaluates to lvalue of type int&.
Therefore, the function wrapper requires training return type declaration, which can be done
in two ways:
auto wrapper( T& op ) -> decltype(op()) in C++11, and
decltype(auto) wrapper( T& op ) in C++14.

10
Programming Questions

Question 1
Consider the following program (in C++14).
• Fill in the blank at LINE-1 with an appropriate template definition.
• Fill in the blank at LINE-2 with an appropriate header for function divide.
The program must satisfy the sample input and output. Marks: 3
#include <iostream>

int convert(double d){


return int(d);
}
double convert(int i){
return double(i);
}

___________________________________ //LINE-1
___________________________________ { //LINE-2
return convert(n1) / convert(n2);
}
int main(){
int a, b;
double c, d;
std::cin >> a >> b >> c >> d;
std::cout << divide(a, b) << " ";
std::cout << divide(a, c) << " ";
std::cout << divide(c, d);
return 0;
}

Public 1
Input: 50 40 30 20
Output:
1.25 1.66667 1

Public 2
Input: 10 6 3 2
Output: 1.66667 3.33333 1

Private
Input: 100 50 70 80
Output: 2 1.42857 0

Answer:
In C++11
LINE-1: template<typename T1, typename T2>
LINE-2: auto divide(T1 n1, T2 n2) -> decltype(convert(n1) / convert(n2))

11
or in C++14

LINE-2: decltype(auto) divide(T1 n1, T2 n2)

Explanation:
Since we can pass two different types of parameters in divide function, we can write at LINE-1:
template<typename T1, typename T2>
The header for function divide in C++11 should be:
auto divide(T1 n1, n2 n2) -> decltype(convert(n1) / convert(n2))
And in C++14:
decltype(auto) divide(T1 n1, T2 n2)
Please any other legal identifier can be used for the typed-parameters.

12
Question 2
Consider the following program (in C++11).

• Fill in the blank at LINE-1 with appropriate header and initialization list for copy con-
structor.

• Fill in the blank at LINE-2 with appropriate header for overloading copy assignment
operator.

• Fill in the blank at LINE-3 with appropriate header and initialization list for move
constructor.

• Fill in the blank at LINE-4 with appropriate header for overloading move assignment
operator.

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

#include <iostream>

class ctype {
public:
ctype() : cp_(nullptr) { }
ctype(char c) : cp_(new char(c)) { }
__________________________ {} // LINE-1: copy constructor
_________________ { // LINE-2: copy assignment
if (this != &ob) {
delete cp_;
cp_ = new char(*(ob.cp_) + 1);
}
return *this;
}
____________________ { // LINE-3: move constructor
ob.cp_ = nullptr;
}
______________ { // LINE-4: move assignment
if (this != &ob) {
cp_ = ob.cp_;
ob.cp_ = nullptr;
}
return *this;
}
void print(){
if(cp_ == nullptr)
std::cout << "moved, ";
else
std::cout << *cp_ << ", ";
}
~ctype() { delete cp_; }
private:
char* cp_ = nullptr;
};
int main(){
char a;

13
std::cin >> a;

ctype c1(a); ctype c2 = c1;


ctype c3 = c1;

c1.print(); c2.print(); c3.print();

ctype c4 = std::move(c1);
ctype c5; c5 = std::move(c1);
c1.print(); c4.print(); c5.print();

return 0;
}

Public 1
Input: A
Output: A, A, A, moved, A, moved,

Public 2
Input: X
Output: X, X, X, moved, X, moved,

Private
Input: z
Output: z, z, z, moved, z, moved,

Answer:
LINE-1: ctype(const ctype& ob) : cp (new char(*(ob.cp )))
LINE-2: ctype& operator=(const ctype& ob)
LINE-3: ctype(ctype&& ob) : cp (ob.cp )
LINE-4: ctype& operator=(ctype&& ob)
Explanation:
At LINE-1, the header and initialization list for copy constructor can be written as:
ctype(const ctype& ob) : cp (new char(*(ob.cp )))
At LINE-2, the header for overloading copy assignment operator can be written as:
ctype& operator=(const ctype& ob)
At LINE-3, the header and initialization list for move constructor can be written as:
ctype(ctype&& ob) : cp (ob.cp )
At LINE-4, the header for overloading move assignment operator can be written as:
ctype& operator=(ctype&& ob)

14
Question 3
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 definition.

• Fill in the blank at LINE-2 to complete the header for function add.

• Fill in the blank at LINE-3 to define the new type Tmp.

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

#include <iostream>

class compex_num{
public:
explicit compex_num(double r = 0, double i = 0) : r_(r), i_(i){}
compex_num operator+(double n){
compex_num res;
res.r_ = this->r_ + n;
res.i_ = this->i_;
return res;
}
compex_num operator+(compex_num c){
compex_num res;
res.r_ = this->r_ + c.r_;
res.i_ = this->i_ + c.i_;
return res;
}
friend std::ostream& operator<<(std::ostream& os, const compex_num& c);
private:
double r_, i_;
};
std::ostream& operator<<(std::ostream& os, const compex_num& c){
os << c.r_ << " + j" << c.i_;
return os;
}

________________________ //LINE-1
________________________ { //LINE-2
______________________________; // LINE-3: define new type Tmp
Tmp sum = n1 + n2;

std::cout << sum << std::endl;


}

int main(){
int a, b, r1, i1, r2, i2;
std::cin >> a >> b >> r1 >> i1 >> r2 >> i2;
compex_num c1(r1, i1);
compex_num c2(r2, i1);
add(c1, a);
add(c1, c2);

15
add(a, b);
return 0;
}

Public 1
Input: 10 20 30 40 50 -60
Output:
40 + j40
80 + j80
30

Public 2
Input: -1 2 3 4 -2 -4
Output:
2 + j4
1 + j8
1

Private
Input: -1 -3 0 1 -1 1
Output:
-1 + j1
-1 + j2
-4

Answer:
LINE-1: template<typename T, typename U>
Or
LINE-1: template<class T, class U>
LINE-2: void add(T& n1, U& n2)
LINE-3: typedef decltype(n1 + n2) Tmp
Explanation:
At LINE-1 the appropriate template can be defined as:
template<typename T, typename U>
or template<class T, class U>
At LINE-2 the header for function add can be written as:
void add(T& n1, U& n2)
At LINE-3 the new type Tmp can be created as:
typedef decltype(n1 + n2) Tmp

16

You might also like