Rule A14-8-2 (required, implementation, automated)
Explicit specializations of function templates shall not be used.
Rationale
Specializations of function templates do not participate in overload resolution. They are only considered after their primary template has been selected during overload resolution. This is highly dependent on the declaration order of overloads and specializations and may be inconsistent with developer expectations. A non-template function is always selected over a function template specialization if they are otherwise an equally good match, which also may be confusing for developers.
Function templates cannot be partially specialized, which may lead to troublesome implementations. If a partial specialization is required, then it is recommended to write a single function template that delegates to a class template (which can be partially specialized).
Example
// $Id: A14-8-2.cpp 312698 2018-03-21 13:17:36Z michal.szczepankiewicz $
#include <cstdint>
#include <memory>
#include <iostream>
template <typename T>
void F1(T t)
{
//compliant, (a)
std::cout << "(a)" << std::endl;
}
template <>
void F1<>(uint16_t* p)
{
//non-compliant
//(x), explicit specialization of
//(a), not (b), due to declaration
//order
std::cout << "(x)" << std::endl;
}
template <typename T>
void F1(T* p)
{
//compliant, (b), overloads (a)
std::cout << "(b)" << std::endl;
}
template <>
void F1<>(uint8_t* p)
{
//non-compliant
//(c), explicit specialization of (b)
std::cout << "(c)" << std::endl;
}
void F1(uint8_t* p)
{
//compliant
//(d), plain function, overloads with (a), (b)
//but not with (c)
std::cout << "(d)" << std::endl;
}
int main(void)
{
auto sp8 = std::make_unique<uint8_t>(3);
auto sp16 = std::make_unique<uint16_t>(3);
F1(sp8.get()); //calls (d), which might be
//confusing, but (c) is non-compliant
F1(sp16.get()); //calls (b), which might be
//confusing, but (b) is non-compliant
}
See also
MISRA C++ 2008 [7]: 14-8-1: Overloaded function templates shall not be explicitly specialized.
MISRA C++ 2008 [7]: 14-8-2: The viable function set for a function call should either contain no function specializations, or only contain function specializations.
HIC++ v4.0 [9]: 14.2.2: Do not explicitly specialize a function template that is overloaded with other templates. C++ Core Guidelines [11]: T.144: Don’t specialize function templates.
Advantages of using exceptions “The exception handling mechanism can provide an effective and clear means of handling error conditions, particularly where a function needs to return both some desired result together with an indication of success or failure. However, because of its ability to transfer control back up the call tree, it can also lead to code that is difficult to understand. Hence it is required that the mechanism is only used to capture behavior that is in some sense undesirable, and which is not expected to be seen in normal program execution.” [MISRA C++ 2008] “The preferred mechanism for reporting errors in a C++ program is exceptions rather than using error codes. A number of core language facilities, including dynamic_cast, operator new(), and typeid, report failures by throwing exceptions. In addition, the C++ standard library makes heavy use of exceptions to report several different kinds of failures. Few C++ programs manage to avoid using some of these facilities.” [ISO C++ Core Guidelines]. Consequently, C++ programs need to be prepared for exceptions to occur and need to handle each appropriately. Challenges of using exceptions Issue:
Solution:
Correctness of the exception handling
Exception handling mechanism is implemented by the compiler (by its library functions and machine code generator) and defined by the C++ Language Standard. Rule A1-2-1 requires that the compiler (including its exception handling routines), when used for safety-related software, meets appropriate safety requirements.
Hidden control flow
ISO 26262-6 (Table *) recommends “no hidden data flow or control flow” for ASIL A software and highly recommends it for ASIL B/C/D. Therefore, the Rule A15-0-1 prohibits the usage of exceptions for normal control flow of software - they are allowed only for errors where a function failed to perform its assigned task.
Guidelines for the use of the C++14 language in critical and safety-related systems
Additional exit point from functions
ISO 26262-6 (Table *) highly recommends “one entry and one exit point in subprograms and functions” for ASIL A software. Therefore, the Rule A15-0-1 prohibits the usage of exceptions for normal control flow of software - they are allowed only for errors where a function failed to perform its assigned task.
Code readability
If exceptions are used correctly, in particularly by using checked and unchecked exception types, see Rules: A15-0-4 and A15-0-5, the code is easier to read and maintain than if using error codes. It avoids nesting if/else error-checking statements.
Exception
safety and program state consistency after exception is thrown
The Rule A15-0-2 requires that functions provide at least “basic exception safety” (Note: this C++ term is not related to functional safety)
Impact on runtime performance
If a function does not throw an exception (i.e. error conditions do not occur), then there could be a little overhead due to exception handling mechanism initialization. However, some compilers offer “zero cost exception handling”, which means that there is no performance overhead if the exception is not thrown.
Impact on worst-case execution time
The A15-0-7 rule requires that the exception handling mechanism provides real-time implementation. Note that this is not the case for e.g. GCC compiler that allocates dynamic memory on throwing an exception. However, it is possible to fix it simply by avoiding memory allocation.
Maturity of exceptions
Exceptions are a widespread concept in several programming languages, not only in C++, but also in e.g. Ada, Java, Modula-3, ML, OCaml, Python, Ruby, C#, Lisp, Eiffel, and Modula-2.
Tool support
There are several tools that support exceptions well: compilers (e.g. gcc, clang, visual studio), IDEs (e.g. eclipse, clion, visual studio), static analysis tools (e.g. QA C++, Coverity Prevent) and compiler validation suites (e.g. SuperTest).
Appropriate usage of exceptions in implementation
Exceptions need to be used properly in the code, therefore this document specifies almost 40 precise rules defining how to code using exceptions, in particular defining the rules for checked/unchecked exceptions.
Table 6.1: Challenges of exceptions usage
Checked and unchecked exceptions
Like MISRA introduces a concept of "underlying type", AUTOSAR C++14 Guidelines introduces a concept of unchecked and checked exceptions. This is based on the classification used in Java language, having as a goal an efficient, complete and consistent way of specifying the exceptions. There are therefore two exclusive categories of exceptions: Checked Exceptions: Used to represent errors that are expected and reasonable to recover from, so they are supposed to be documented by functions using a dedicated tag (e.g. @throws) and have to be either handled or documented (in the same way) by caller functions. Exceptions are marked as Checked using a separate tag (e.g. @checkedException) that precedes an exception class declaration. Unchecked Exceptions: Used to represent errors that a program typically can not recover from. However, unchecked exceptions can be documented by functions, i.e in cases when all preconditions of thrown exception are defined and known. It is context dependent where such an exception can be caught (e.g. is it done before main function) and what is the proper handling (e.g. other than program termination). However, it is not forced so that unchecked exceptions are documented by caller functions (even if they are documented by called functions). By default, all exceptions are unchecked (also from third-party libraries used), unless their definition is preceded by the dedicated tag. “Checked exceptions are a wonderful feature of the Java programming language. Unlike return codes, they force the programmer to deal with exceptional conditions, greatly enhancing reliability.” [Effective Java 2nd Edition [15]] The following sections specify several specific rules defining the usage of exceptions, in particular concerning the use of unchecked and checked exceptions.