This rule is part of MISRA C++:2023.
Usage of this content is governed by Sonar’s terms and conditions. Redistribution is
prohibited.
Rule 6.4.3 - A name that is present in a dependent base shall not be resolved by unqualified lookup
[basic.lookup.unqual]
Category: Required
Analysis: Decidable,Single Translation Unit
Amplification
This rule applies to names that would be found by unqualified lookup if none of the base classes were dependent.
Note: this rule does not apply to names from a base class that are introduced into the derived class through a using [1]
declaration.
Rationale
For a template class with a dependent base, the use of an unqualified name that does not refer to an entity in that class is taken to mean
an entity in global scope, even if there is an entity with that name in the base. This differs from the behaviour in non-template
classes, where the entity in the base will be selected in preference to an entity in global scope. This may not be consistent with
developer expectations.
Note: using a qualified-id or prefixing the identifier with this-> ensures that an entity in the
base is selected.
Example
using int32_t = int;
using int16_t = short;
typedef int32_t Type;
void g();
template< typename T > struct B;
template< typename T >
struct A : B< T >
{
using typename B< T >::ConstType;
void f1()
{
// Non-compliant for A< int32_t > - compiler will choose ::Type
// If B were non-dependent, B< int32_t>::Type would have been chosen
// Non-compliant for A< int16_t > - compiler will choose ::Type
// If B were non-dependent, B< int16_t>::Type would have been chosen
Type t = 0;
// Compliant - compiler finds the name introduced by the using declaration
ConstType t = 0;
// Non-compliant for A< int32_t > - compiler will choose ::g
// If B were non-dependent, B< int32_t>::g would have been chosen
// Compliant for A< int16_t > - base B< int16_t > has no member g
g();
}
void f2()
{
::Type t1 = 0; // Compliant - explicit use of global Type
::g(); // Compliant - explicit use of global g
typename B< T >::Type t2 = 0; // Compliant - explicit use of base Type
// Compliant for A< int32_t > - uses base g
// Compile error for A< int16_t >
this->g();
}
};
template< typename T >
struct B
{
typedef T Type;
typedef T const ConstType;
void g();
};
template<> struct B< int16_t >
{
typedef int16_t Type;
typedef int16_t const ConstType;
};
template struct A< int32_t >;
template struct A< int16_t >;
using value_type = char16_t;
template< typename String >
class MyString : public String
{
// Non-compliant for MyString<std::string> - compiler will choose ::value_type
// If MyString inherited directly from std::string, std::string::value_type
// would have been chosen
value_type separator;
};
MyString< std::string > ms;
Glossary
[1] Use / used / using
An object is used if:
- It is the subject of a cast; or
- It is explicitly initialized at declaration time; or
- It is an operand in an expression; or
- It is referenced.
A function is used as defined in M23_331: MISRA C++ 2023 Rule 0.2.4.
A type is used as defined in M23_005: MISRA C++ 2023 Rule 0.2.3.
Copyright The MISRA Consortium Limited © 2023