c++ questions (10 q&a)
note: iso c++ n4860 draft is used.
if something wrong with the questions, you can report via github issues.
'what's the output' means, if you see nothing wrong with the code (including ub and impl. defined situations); it would be the answer.
if not, it can be error, undefined behavior or implementation defined.
question 1: what's the output?
#include <iostream>
#include <string>
template<typename X, typename Y>
unsigned Function(X x, Y y) noexcept {
if constexpr(std::is_same_v<X, Y>) {
return 13;
}
return 0;
}
int main() {
const int value = 13;
enum Value: const unsigned { Val = value };
std::cout << Function(value, Value::Val) << '\n';
}
question 2: what's the output?
#include <iostream>
#include <iomanip>
class Class {
int Value;
public:
explicit Class(int value) : Value(value) {}
int GetValue() noexcept {
return this->Value;
}
static inline int Function(Class value) {
return value.GetValue();
}
};
int main() {
std::cout << std::boolalpha << (Class::Function('g') == static_cast<int>('g')) << '\n';
}
question 3: what's the output?
#include <iostream>
#include <vector>
#include <type_traits>
#include <iomanip>
#include <typeinfo>
#include <any>
int main() {
std::vector<bool> Val {
false,
true,
false,
false,
false,
true,
true,
true,
};
std::any value = Val.front();
std::cout << std::boolalpha << (value.type().hash_code() == typeid(bool).hash_code()) << '\n';
}
question 4: what's the output?
#include <iostream>
class Y {
public:
Y() = default;
~Y() = default;
class Z {
public:
Z() = default;
~Z() = default;
};
};
class Q {
public:
template<typename Val>
void Data(Val::Z value) {
return;
}
void Data(int value) {
std::cout << value << '\n';
}
};
int main() {
Q q;
q.Data(13);
}
question 5: what's the output?
int Function(int arg) noexcept {
static int value = Function(arg + 1);
return arg + 1;
}
int main() {
return Function(0);
}
question 6: what's the output?
#include <iostream>
int main() noexcept((nullptr == NULL)) {
std::cout << '0' << '\n';
throw 0;
}
question 7: what's the output?
#include <iostream>
int main() {
if(!nullptr) {
std::cout <<'1'<< '\n';
} else {
std::cout <<'0'<< '\n';
}
}
question 8: what's the output?
#include <iostream>
int main() noexcept(true) {
std::int8_t value = 255;
++value;
std::cout << value << '\n';
}
question 9: what's the output?
#include <iostream>
#include <functional>
class X {
public:
void Function(std::function<int()> func = []() {
return 13;
}) {
std::cout << func() << '\n';
}
};
int Function() {
return 0;
}
int main() {
X x;
x.Function(Function);
x.Function();
x.Function([](){ return 2; });
}
question 10: what's the output?
template<typename X, typename Y = int>
void Function(X argument, Y argument2 = 13) {
return;
}
int main() {
Function<double>(13.0);
Function<double, double>(13.0, 2.0);
Function();
}
.
.
.
.
answers:
question 1:
9.7.1:5 [dcl.enum] says that,
Each enumeration defines a type that is different from all other types.
Each enumeration also has an underlying
type. The underlying type can be explicitly specified using an enum-base. For a scoped enumeration type, the
underlying type is int if it is not explicitly specified. In both of these cases, the underlying type is said to be
fixed. Following the closing brace of an enum-specifier, each enumerator has the type of its enumeration. If
the underlying type is fixed, the type of each enumerator prior to the closing brace is the underlying type and
the constant-expression in the enumerator-definition shall be a converted constant expression of the underlying
type (7.7). If the underlying type is not fixed, the type of each enumerator prior to the closing brace is
determined as follows:
— If an initializer is specified for an enumerator, the constant-expression shall be an integral constant
expression (7.7). If the expression has unscoped enumeration type, the enumerator has the underlying
type of that enumeration type, otherwise it has the same type as the expression.
— If no initializer is specified for the first enumerator, its type is an unspecified signed integral type.
— Otherwise the type of the enumerator is the same as that of the preceding enumerator unless the
incremented value is not representable in that type, in which case the type is an unspecified integral
type sufficient to contain the incremented value. If no such type exists, the program is ill-formed.
so, correct answer is 0
question 2:
11.4.7.1:2 [class.conv.ctor] says that,
...An explicit constructor constructs objects just like non-explicit constructors, but does so only where the
direct-initialization syntax (9.4) or where casts (7.6.1.8, 7.6.3) are explicitly used; see also 12.4.1.4. A default
constructor may be an explicit constructor; such a constructor will be used to perform default-initialization
or value-initialization (9.4)...
so, this code won't be compiled due compile errors.
question 3:
22.3.12:3 [vector.bool] says that,
There is no requirement that the data be stored as a contiguous allocation of bool values. A space-optimized
representation of bits is recommended instead
it's implementation defined. so depends on the compiler.
question 4:
13.10.3:1 [temp.over] and 13.10.2:7 [temp.deduct] says that,
When a call to the name of a function or function template is written (explicitly, or implicitly using the operator
notation), template argument deduction (13.10.2) and checking of any explicit template arguments (13.4)
are performed for each function template to find the template argument values (if any) that can be used
with that function template to instantiate a function template specialization that can be invoked with
the call arguments. For each function template, if the argument deduction and checking succeeds, the
template-arguments (deduced and/or explicit) are used to synthesize the declaration of a single function
template specialization which is added to the candidate functions set to be used in overload resolution. If,
for a given function template, argument deduction fails or the synthesized function template specialization
would be ill-formed, no such function is added to the set of candidate functions for that template. The
complete set of candidate functions includes all the synthesized declarations and all of the non-template
overloaded functions of the same name. The synthesized declarations are treated like any other functions in
the remainder of overload resolution, except as explicitly noted in 12.4.3.
The substitution occurs in all types and expressions that are used in the function type and in template
parameter declarations. The expressions include not only constant expressions such as those that appear in
array bounds or as nontype template arguments but also general expressions (i.e., non-constant expressions)
inside sizeof, decltype, and other contexts that allow non-constant expressions. The substitution proceeds
in lexical order and stops when a condition that causes deduction to fail is encountered. If substitution into
different declarations of the same function template would cause template instantiations to occur in a different
order or not at all, the program is ill-formed; no diagnostic required. [Note: The equivalent substitution in
exception specifications is done only when the noexcept-specifier is instantiated, at which point a program is
ill-formed if the substitution results in an invalid type or expression...
correct answer is 13. this state called as sfinae, which means substitution failure is not an error.
question 5:
8.8:4 [stmt.dcl] says that,
Dynamic initialization of a block-scope variable with static storage duration (6.7.5.1) or thread storage
duration (6.7.5.2) is performed the first time control passes through its declaration; such a variable is
considered initialized upon the completion of its initialization. If the initialization exits by throwing an
exception, the initialization is not complete, so it will be tried again the next time control enters the declaration.
If control enters the declaration concurrently while the variable is being initialized, the concurrent execution
shall wait for completion of the initialization.85 If control re-enters the declaration recursively while the
variable is being initialized, the behavior is undefined.
correct answer is undefined behavior.
question 6:
7.3.11:1 [conv.ptr] says that,
A null pointer constant is an integer literal (5.13.2) with value zero or a prvalue of type std::nullptr_t. A
null pointer constant can be converted to a pointer type; the result is the null pointer value of that type (6.8.2)
and is distinguishable from every other value of object pointer or function pointer type. Such a conversion
is called a null pointer conversion. Two null pointer values of the same type shall compare equal. The
conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the
sequence of a pointer conversion followed by a qualification conversion (7.3.5). A null pointer constant of
integral type can be converted to a prvalue of type std::nullptr_t. [Note: The resulting prvalue is not a
null pointer value.
so, this code won't be compiled due compile errors.
question 7:
7.3.14:1 [conv.bool] says that,
A prvalue of arithmetic, unscoped enumeration, pointer, or pointer-to-member type can be converted to a
prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false;
any other value is converted to true.
correct answer is 1.
question 8:
7.7:5.7 [expr.const] says that,
an operation that would have undefined behavior as specified in Clause 4 through Clause 15 of this
document [Note: including, for example, signed integer overflow (7.2), certain pointer arithmetic (7.6.6),
division by zero (7.6.5), or certain shift operations (7.6.7)...
correct answer is undefined behavior.
question 9:
9.3.3.6:1 [dcl.fct.default] and 9.3.3.6:3 [dcl.fct.default] says that,
If an initializer-clause is specified in a parameter-declaration this initializer-clause is used as a default argument.
[Note: Default arguments will be used in calls where trailing arguments are missing (7.6.1.2)...
A default argument shall be specified only in the parameter-declaration-clause of a function declaration
or lambda-declarator or in a template-parameter (13.2); in the latter case, the initializer-clause shall be an
assignment-expression. A default argument shall not be specified for a template parameter pack or a function
parameter pack. If it is specified in a parameter-declaration-clause, it shall not occur within a declarator or
abstract-declarator of a parameter-declaration.
correct answer is 0 13 2.
question 10:
13.10.2:5 [temp.deduct] says that,
The resulting substituted and adjusted function type is used as the type of the function template for template
argument deduction. If a template argument has not been deduced and its corresponding template parameter
has a default argument, the template argument is determined by substituting the template arguments
determined for preceding template parameters into the default argument. If the substitution results in an
invalid type, as described above, type deduction fails...
so, this code won't be compiled due compile errors at 'Function()'
definitions from c++20 iso draft:
implementation-defined behavior, 3.13 [defns.impl.defined]:
behavior, for a well-formed program construct and correct data, that depends on the implementation and
that each implementation document
undefined behavior, 3.30 [defns.undefined]:
behavior for which this document imposes no requirements
[Note 1 to entry: Undefined behavior may be expected when this document omits any explicit definition of
behavior or when a program uses an erroneous construct or erroneous data. Permissible undefined behavior
ranges from ignoring the situation completely with unpredictable results, to behaving during translation or
program execution in a documented manner characteristic of the environment (with or without the issuance
of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).
Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed...
unspecified behavior, 3.31 [defns.unspecified]:
behavior, for a well-formed program construct and correct data, that depends on the implementation
[Note 1 to entry: The implementation is not required to document which behavior occurs. The range of
possible behaviors is usually delineated by this document...
if you think about the answers or anything else is wrong,
please create an issue from github issues.