What does the explicit keyword mean?
Solution 1
The compiler is allowed to make one implicit conversion to resolve the parameters to a function. What this means is that the compiler can use constructors callable with a single parameter to convert from one type to another in order to get the right type for a parameter.
Here's an example class with a constructor that can be used for implicit conversions:
class Foo
{
private:
int m_foo;
public:
// single parameter constructor, can be used as an implicit conversion
Foo (int foo) : m_foo (foo) {}
int GetFoo () { return m_foo; }
};
Here's a simple function that takes a Foo
object:
void DoBar (Foo foo)
{
int i = foo.GetFoo ();
}
and here's where the DoBar
function is called:
int main ()
{
DoBar (42);
}
The argument is not a Foo
object, but an int
. However, there exists a constructor for Foo
that takes an int
so this constructor can be used to convert the parameter to the correct type.
The compiler is allowed to do this once for each parameter.
Prefixing the explicit
keyword to the constructor prevents the compiler from using that constructor for implicit conversions. Adding it to the above class will create a compiler error at the function call DoBar (42)
. It is now necessary to call for conversion explicitly with DoBar (Foo (42))
The reason you might want to do this is to avoid accidental construction that can hide bugs.
Contrived example:
- You have a
MyString
class with a constructor that constructs a string of the given size. You have a functionprint(const MyString&)
(as well as an overloadprint (char *string)
), and you callprint(3)
(when you actually intended to callprint("3")
). You expect it to print "3", but it prints an empty string of length 3 instead.
Solution 2
Suppose, you have a class String
:
class String {
public:
String(int n); // allocate n bytes to the String object
String(const char *p); // initializes object with char *p
};
Now, if you try:
String mystring = 'x';
The character 'x'
will be implicitly converted to int
and then the String(int)
constructor will be called. But, this is not what the user might have intended. So, to prevent such conditions, we shall define the constructor as explicit
:
class String {
public:
explicit String (int n); //allocate n bytes
String(const char *p); // initialize sobject with string p
};
Solution 3
In C++, a constructor with only one required parameter is considered an implicit conversion function. It converts the parameter type to the class type. Whether this is a good thing or not depends on the semantics of the constructor.
For example, if you have a string class with constructor String(const char* s)
, that's probably exactly what you want. You can pass a const char*
to a function expecting a String
, and the compiler will automatically construct a temporary String
object for you.
On the other hand, if you have a buffer class whose constructor Buffer(int size)
takes the size of the buffer in bytes, you probably don't want the compiler to quietly turn int
s into Buffer
s. To prevent that, you declare the constructor with the explicit
keyword:
class Buffer { explicit Buffer(int size); ... }
That way,
void useBuffer(Buffer& buf);
useBuffer(4);
becomes a compile-time error. If you want to pass a temporary Buffer
object, you have to do so explicitly:
useBuffer(Buffer(4));
In summary, if your single-parameter constructor converts the parameter into an object of your class, you probably don't want to use the explicit
keyword. But if you have a constructor that simply happens to take a single parameter, you should declare it as explicit
to prevent the compiler from surprising you with unexpected conversions.
Solution 4
The keyword explicit
accompanies either
- a constructor of class X that cannot be used to implicitly convert the first (any only) parameter to type X
C++ [class.conv.ctor]
1) A constructor declared without the function-specifier explicit specifies a conversion from the types of its parameters to the type of its class. Such a constructor is called a converting constructor.
2) An explicit constructor constructs objects just like non-explicit constructors, but does so only where the direct-initialization syntax (8.5) or where casts (5.2.9, 5.4) are explicitly used. A default constructor may be an explicit constructor; such a constructor will be used to perform default-initialization or valueinitialization (8.5).
- or a conversion function that is only considered for direct initialization and explicit conversion.
C++ [class.conv.fct]
2) A conversion function may be explicit (7.1.2), in which case it is only considered as a user-defined conversion for direct-initialization (8.5). Otherwise, user-defined conversions are not restricted to use in assignments and initializations.
Overview
Explicit conversion functions and constructors can only be used for explicit conversions (direct initialization or explicit cast operation) while non-explicit constructors and conversion functions can be used for implicit as well as explicit conversions.
/*
explicit conversion implicit conversion
explicit constructor yes no
constructor yes yes
explicit conversion function yes no
conversion function yes yes
*/
Example using structures X, Y, Z
and functions foo, bar, baz
:
Let's look at a small setup of structures and functions to see the difference between explicit
and non-explicit
conversions.
struct Z { };
struct X {
explicit X(int a); // X can be constructed from int explicitly
explicit operator Z (); // X can be converted to Z explicitly
};
struct Y{
Y(int a); // int can be implicitly converted to Y
operator Z (); // Y can be implicitly converted to Z
};
void foo(X x) { }
void bar(Y y) { }
void baz(Z z) { }
Examples regarding constructor:
Conversion of a function argument:
foo(2); // error: no implicit conversion int to X possible
foo(X(2)); // OK: direct initialization: explicit conversion
foo(static_cast<X>(2)); // OK: explicit conversion
bar(2); // OK: implicit conversion via Y(int)
bar(Y(2)); // OK: direct initialization
bar(static_cast<Y>(2)); // OK: explicit conversion
Object initialization:
X x2 = 2; // error: no implicit conversion int to X possible
X x3(2); // OK: direct initialization
X x4 = X(2); // OK: direct initialization
X x5 = static_cast<X>(2); // OK: explicit conversion
Y y2 = 2; // OK: implicit conversion via Y(int)
Y y3(2); // OK: direct initialization
Y y4 = Y(2); // OK: direct initialization
Y y5 = static_cast<Y>(2); // OK: explicit conversion
Examples regarding conversion functions:
X x1{ 0 };
Y y1{ 0 };
Conversion of a function argument:
baz(x1); // error: X not implicitly convertible to Z
baz(Z(x1)); // OK: explicit initialization
baz(static_cast<Z>(x1)); // OK: explicit conversion
baz(y1); // OK: implicit conversion via Y::operator Z()
baz(Z(y1)); // OK: direct initialization
baz(static_cast<Z>(y1)); // OK: explicit conversion
Object initialization:
Z z1 = x1; // error: X not implicitly convertible to Z
Z z2(x1); // OK: explicit initialization
Z z3 = Z(x1); // OK: explicit initialization
Z z4 = static_cast<Z>(x1); // OK: explicit conversion
Z z1 = y1; // OK: implicit conversion via Y::operator Z()
Z z2(y1); // OK: direct initialization
Z z3 = Z(y1); // OK: direct initialization
Z z4 = static_cast<Z>(y1); // OK: explicit conversion
Why use explicit
conversion functions or constructors?
Conversion constructors and non-explicit conversion functions may introduce ambiguity.
Consider a structure V
, convertible to int
, a structure U
implicitly constructible from V
and a function f
overloaded for U
and bool
respectively.
struct V {
operator bool() const { return true; }
};
struct U { U(V) { } };
void f(U) { }
void f(bool) { }
A call to f
is ambiguous if passing an object of type V
.
V x;
f(x); // error: call of overloaded 'f(V&)' is ambiguous
The compiler does not know wether to use the constructor of U
or the conversion function to convert the V
object into a type for passing to f
.
If either the constructor of U
or the conversion function of V
would be explicit
, there would be no ambiguity since only the non-explicit conversion would be considered. If both are explicit the call to f
using an object of type V
would have to be done using an explicit conversion or cast operation.
Conversion constructors and non-explicit conversion functions may lead to unexpected behaviour.
Consider a function printing some vector:
void print_intvector(std::vector<int> const &v) { for (int x : v) std::cout << x << '\n'; }
If the size-constructor of the vector would not be explicit it would be possible to call the function like this:
print_intvector(3);
What would one expect from such a call? One line containing 3
or three lines containing 0
? (Where the second one is what happens.)
Using the explicit keyword in a class interface enforces the user of the interface to be explicit about a desired conversion.
As Bjarne Stroustrup puts it (in "The C++ Programming Language", 4th Ed., 35.2.1, pp. 1011) on the question why std::duration
cannot be implicitly constructed from a plain number:
If you know what you mean, be explicit about it.
Solution 5
This answer is about object creation with/without an explicit constructor since it is not covered in the other answers.
Consider the following class without an explicit constructor:
class Foo
{
public:
Foo(int x) : m_x(x)
{
}
private:
int m_x;
};
Objects of class Foo can be created in 2 ways:
Foo bar1(10);
Foo bar2 = 20;
Depending upon the implementation, the second manner of instantiating class Foo may be confusing, or not what the programmer intended. Prefixing the explicit
keyword to the constructor would generate a compiler error at Foo bar2 = 20;
.
It is usually good practice to declare single-argument constructors as explicit
, unless your implementation specifically prohibits it.
Note also that constructors with
- default arguments for all parameters, or
- default arguments for the second parameter onwards
can both be used as single-argument constructors. So you may want to make these also explicit
.
An example when you would deliberately not want to make your single-argument constructor explicit is if you're creating a functor (look at the 'add_x' struct declared in this answer). In such a case, creating an object as add_x add30 = 30;
would probably make sense.
Here is a good write-up on explicit constructors.
Skizz
I first started programming aged nine in Basic on a Sinclair ZX80, quickly progressing onto Z80 machine code on the ZX Spectrum. This led to the PC platform, an Amstrad 1512, where I learned various flavours of BASIC and 8086 programming, even doing some very rudimentary 3D graphics. Up until this point, everything had been self taught. In 1988 I went to Bradford University to study for an Electronic / Software Engineering degree. This was a thin sandwich style course over four years, the first three were split six months at university and six months on placement in industry. The first year introduced the Pascal programming language and the Unix operating system at university and C during the placement. Subsequent years concentrated on C and assembly language for various platforms – mainly Motorola and Transputer based as well as Sun Unix systems. Upon completing my degree I developed and had published my first PC game. This led the way to further jobs in the games industry and it wasn't long before C++ became the language of choice for work. In 2004 I began branching out on my own to work on business solutions. My interest in programming goes beyond work related projects. I spend my spare time looking into new technologies and new languages. I have recently configured a linux server for my home network, built some small, personal websites and tools to update the databases that sit behind the sites. I purchased a Raspberry Pi which I use to develop linux based software using python, OpenGL|ES, etc., as well as building some electronic circuits to interface to the device.
Updated on April 20, 2022Comments
-
Skizz about 2 years
What does the
explicit
keyword mean in C++?-
chris over 11 yearsI just want to point out to anyone new coming along that ever since C++11,
explicit
can be applied to more than just constructors. It's now valid when applied to conversion operators as well. Say you have a classBigInt
with a conversion operator toint
and an explicit conversion operator tostd::string
for whatever reason. You'll be able to sayint i = myBigInt;
, but you'll have to cast explicitly (usingstatic_cast
, preferably) in order to saystd::string s = myBigInt;
. -
Eitan Myron about 10 yearsCan't explicit also refer to assignment? (i.e.
int x(5);
) -
curiousguy almost 6 years@chris The idea of an explicit implicit conversion is absurd. Stay clear of it!
-
chris almost 6 years@curiousguy, There's no such thing as an explicit implicit conversion.
-
curiousguy almost 6 years@chris There is an explicit keyword that can be used on the declaration of an implicit conversion.
-
chris almost 6 years@curiousguy, It's not inherently an implicit conversion. Putting
explicit
there declares an explicit conversion to a type. No implicitness involved in the process. -
curiousguy almost 6 years@chris Explicit conversion is an ill defined concept.
-
Sz. over 4 years@curiousguy: What do you mean? All conversions should be implicit? To let loose all sorts of silently applied funny miscasts due to accidental ambiguities? (See e.g. the "The safe bool problem" section at this C++ref. page, or open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2333.html for (much) more details on why "Explicit conversion is an ill defined concept." is an ill-conceived statement.)
-
curiousguy over 4 years@Sz. I mean that explicit conversion is not a thing; it's a garbage concept. Also the "safe bool" is a ridiculous "proof" for the usefulness of the "explicit operator" idea as it isn't even an application of that idea but a different set of rules, which means the only practical use of "explicit operator" in the SL is ad hoc and not applicable to UDT.
-
Milan over 3 years@chris did you mean like this:
std::string s = static_cast<std::string>(myBigInt)
? If possible, could you please elaborate furthermore on your first comment? Thanks a lot in advance! -
chris over 3 years@Milan, Yes, that's exactly it. If you're looking for more information, this answer writes it up more formally. Do note that
bool
is special in this regard. Those answers and searching "explicit conversion operators" will lead you to more writeups about this feature and be better suited than a comment chain.
-
-
0xCAFEBABE over 15 yearsnice write up, you might want to mention multi-arg ctors with default params can also act as single arg ctor, e.g., Object( const char* name=NULL, int otype=0).
-
Michael Burr over 14 yearsI think it should also be mentioned that one should consider making single argument constructors explicit initially (more or less automatically), and removing the explicit keyword only when the implicit conversion is wanted by design. I think contructors should be explicit by default with an 'implicit' keyword to enable them to work as implicit conversions. But that's not how it is.
-
Johannes Schaub - litb over 13 yearsAnd it's worth noting that the new generalized initialization rules of C++0x will make
String s = {0};
ill-formed, rather than trying to call the other constructor with a null pointer, asString s = 0;
would do. -
Christian Severin almost 13 years@thecoshman: You don't declare a parameter
explicit
-- you declare a constructorexplicit
. But yes: your parameters of typeFoo
have to be constructedexplicite
ly, they won't be silently constructed by just plugging their constructor's parameters into the function. -
Larry almost 12 yearsJust an FYI that when calling "print(3)" in your example, the function needs to be "print(const MyString &"). The "const" is mandatory here because 3 is converted to a temporary "MyString" object and you can't bind a temporary to a reference unless it's "const" (yet another in a long list of C++ gotchas)
-
Arbalest over 11 yearsFor completeness sake, I am adding that in addition to parameter conversion the explicit keyword here will also prevent the use of assignment form of a copy ctor (e.g., Foo myFoo = 42;) and require the explicit forms Foo myFoo = Foo(42); or Foo myFoo(42);
-
Arbalest over 10 yearsEven though this is an old question it seems worth pointing a few things out (or having someone set me straight). By making the int form, or both ctors, 'explicit' you would still have the same bug if you used
String mystring('x')
when you meantString mystring("x")
wouldn't you? Also, from the comment above I see the improved behavior ofString s = {0}
overString s = 0
thanks to making the int form of the ctor 'explicit'. But, other than knowing the precedence of the ctors how do you know the intent (i.e. how to spot the bug) of thisString s{0}
? -
6502 about 10 years
C c();
in the first example doesn't mean what you think it means: it's the declaration of a function namedc
that takes no parameters and returns an instance ofC
. -
InQusitive about 9 yearsWhy String mystring = 'x'; is getting converted to int?
-
DavidRR almost 9 years@InQusitive:
'x'
is being treated as an integer because thechar
data type is just a 1-byte integer. -
Maggyero over 8 yearsThe problem with your example is that it only works with copy initialization (using
=
) but not with direct initialization (without using=
): the compiler will still call theString(int)
constructor without generating an error if you writeString mystring('x');
, as @Arbalest pointed out. Theexplicit
keyword is meant for preventing implicit conversions that happen in direct initialization and function resolution. A better solution to your example would be a simple overload of the constructor:String(char c);
. -
v010dya over 8 yearsThis post is written in 2009. Today you don't declare them as private, but rather say
= delete
. -
Justin Time - Reinstate Monica about 8 years
explicit operator bool()
is also the C++11 version of safe bool, and can be used implicitly in condition checks (and only in condition checks, as far as I'm aware). In your second example, this line would also be valid inmain()
:if (c) { std::cout << "'c' is valid." << std:: endl; }
. Apart from this, though, it can't be used without explicit casting. -
pqnet almost 7 years
useBuffer
expects an lvalue for his argument,useBuffer(Buffer(4))
will not work either because of it. Changing it to take aconst Buffer&
orBuffer&&
or justBuffer
would make it work. -
curiousguy almost 6 years
explicit operator bool()
vs.if
is a special case. There is no way to reproduce it with user definedBool
,explicit operator Bool()
and a function calledIf
. -
curiousguy almost 6 years"constructor to be called explicitly" no
-
curiousguy almost 6 years@JustinTime It's an inane, broken version of the safe bool. The whole idea of explicit implicit conversion is absurd.
-
Justin Time - Reinstate Monica almost 6 years@curiousguy True. It seems a bit like a kludge, aimed more at being easily remembered (likely in the hopes of that translating to frequently used) than at following English logic, and designed to not be outright incompatible with previous safe bool implementations (so you're less likely to break something if you swap it in). IMO, at least.
-
mosegui about 3 yearsBut, if I understand your latter counter-example correctly,
print("3")
should yield a compiling error since the functionprint
is actually expecting aMyString
instance, and not an actual string, and the constructor of theMyString
class does not allow the compiler to automatically cast the string"3"
to aMyString
object. Am I understanding it wrong? -
Skizz about 3 years@mosegui: yes, you're right, as given in the answer. I should have said that there was an overload of print that took a char *. I'll modify the answer.
-
JDługosz over 2 yearsI edited this to fix the
C c();
and also played around in Compiler Explorer and it appears that making a default constructorexplicit
doesn't actually do anything. This answer is simply wrong, even with the code corrections already made. -
Skizz over 2 years@66Gramms: Your changes to the code in this answer only make it more readable to you, to some people, including me, the code is less readable. Please don't edit answers to change the coding style to suit your preferences.