
Inline adoc files when they are included exactly once. Also fix language tags because this inlining gives us better information on what language the code is written in.
102 lines
3.9 KiB
Plaintext
102 lines
3.9 KiB
Plaintext
== Why is this an issue?
|
|
|
|
If you invoked a method with arguments of the wrong type, you would typically expect an error at compile time (if not in the IDE). However, when the expected parameter is a class with a single-argument constructor, the compiler will implicitly pass the method argument to that constructor to implicitly create an object of the correct type for the method invocation. Alternately, if the wrong type has a conversion operator to the correct type, the operator will be called to create an object of the needed type.
|
|
|
|
|
|
But just because you _can_ do something, that doesn't mean you _should_, and using implicit conversions makes the execution flow difficult to understand. Readers may not notice that a conversion occurs, and if they do notice, it will raise a lot of questions: Is the source type able to convert to the destination type? Is the destination type able to construct an instance from the source? Is it both? And if so, which method is called by the compiler?
|
|
|
|
|
|
Moreover, implicit promotions can lead to unexpected behavior, so they should be prevented by using the ``++explicit++`` keyword on single-argument constructors and ({cpp}11) conversion operators. Doing so will prevent the compiler from performing implicit conversions.
|
|
|
|
|
|
=== Noncompliant code example
|
|
|
|
[source,cpp]
|
|
----
|
|
struct Bar {
|
|
};
|
|
|
|
struct Foo {
|
|
Foo(Bar& bar); // Noncompliant; allow implicit conversion from 'Bar' to 'Foo'
|
|
};
|
|
|
|
struct Baz {
|
|
operator Foo(); // Noncompliant; allow implicit conversion from 'Baz' to 'Foo'
|
|
};
|
|
|
|
void func(const Foo& b); // this function needs a 'Foo' not a 'Bar' nor a 'Baz'
|
|
|
|
int test(Bar& bar, Baz& baz) {
|
|
func(bar); // implicit conversion using Foo::Foo(Bar& bar)
|
|
func(baz); // implicit conversion using Baz::operator Foo()
|
|
func(baz);
|
|
}
|
|
----
|
|
|
|
|
|
=== Compliant solution
|
|
|
|
[source,cpp]
|
|
----
|
|
struct Bar {
|
|
};
|
|
|
|
struct Foo {
|
|
explicit Foo(Bar& bar); // Compliant, using "explicit" keyword
|
|
};
|
|
|
|
struct Baz {
|
|
Foo asFoo(); // Compliant, explicit function
|
|
explicit operator Foo(); // Compliant, using C++11 "explicit" keyword for conversion function
|
|
};
|
|
|
|
void func(const Foo& b); // this function needs a 'Foo' not a 'Bar' nor a 'Baz'
|
|
|
|
int test(Bar& bar, Baz& baz) {
|
|
func(Foo(bar)); // explicit conversion using Foo::Foo(Bar& bar)
|
|
func(baz.asFoo()); // explicit conversion using Baz::asFoo()
|
|
func(static_cast<Foo>(baz)); // explicit conversion using Baz::operator Foo()
|
|
}
|
|
----
|
|
|
|
=== Exceptions
|
|
|
|
{cpp}20 introduced conditional `explicit(expr)` that allows developers to make a constructor or conversion operator conditionally explicit depending on the value of `expr`.
|
|
The new syntax allows a constructor or conversion operator declared with an `explicit(expr)` specifier to be implicit when `expr` evaluates to `false`.
|
|
The issue is not raised in such situation.
|
|
|
|
Additionally, developers can use `explicit(false)` to mark constructors or conversion operators as intentionally implicit.
|
|
|
|
== Resources
|
|
|
|
* MISRA {cpp}:2008, 12-1-3 - All constructors that are callable with a single argument of fundamental type shall be declared ``++explicit++``.
|
|
* https://github.com/isocpp/CppCoreGuidelines/blob/036324/CppCoreGuidelines.md#c46-by-default-declare-single-argument-constructors-explicit[{cpp} Core Guidelines C.46] - By default, declare single-argument constructors explicit
|
|
* https://github.com/isocpp/CppCoreGuidelines/blob/036324/CppCoreGuidelines.md#c164-avoid-implicit-conversion-operators[{cpp} Core Guidelines C.164] - Avoid implicit conversion operators
|
|
|
|
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
=== Message
|
|
|
|
* Add the "explicit" keyword to this constructor.
|
|
* Replace this conversion operator with a function or ({cpp}11) add the "explicit" keyword.
|
|
|
|
|
|
=== Highlighting
|
|
|
|
constructor or conversion operator id
|
|
|
|
|
|
'''
|
|
== Comments And Links
|
|
(visible only on this page)
|
|
|
|
=== is duplicated by: S1021
|
|
|
|
endif::env-github,rspecator-view[]
|