explicit non-single parameter constructor - c++

Can anyone explain why does non-single parameter constructor marked as explicit compile?
As far as I understand this is absolutely useless keyword here, so why does this compile without error?
class X
{
public:
explicit X(int a, int b) { /* ... */}
};

In C++03, and in this particular case, it makes no sense for a two parameter constructor to be marked explicit. But it could make sense here:
explicit X(int i, int j=42);
So, marking a two parameter constructor with explicit does not have to be an error.
In C++11, this use of explicit would prevent you from doing this:
X x = {1,2};

Not entirely true.
In C++11, constructors with multiple arguments can be implicitly converted using brace initialisation.

Related

Why is the constructor of std::in_place_t defaulted and explicit?

cppreference shows the following definition of std::in_place_t:
struct in_place_t {
explicit in_place_t() = default;
};
inline constexpr std::in_place_t in_place{};
Why have they added an explicit and defaulted constructor? Why it isn't left out? What are the benefits?
You want a type like this to only be explicitly constructible, because it exists to denote a particular kind of constructor overload, in places where {} might reasonably be found.
Consider the following constructions
std::optional<DefaultConstructible> dc1({}); // dc1 == std::nullopt
std::optional<DefaultConstructible> dc2(std::in_place); // dc2 == DefaultConstructible()
If you leave out the constructor it will not be explicit. If you don't = default it it will not be trivial.
So, if you want the constructor to be explicit and you also want it to remain trivial, what you see is the only option available.

How can I avoid most vexing parse with direct value initialization?

After reading Most vexing parse, I understand the following code is also ambiguous
T x();
On the one hand, it can be interpreted as a function declaration which returns an object of T. On the other hand, it can also be interpreted as a variable definition, and object x is value-initialized.
I understand I can use uniform initialization like the following code to avoid conflict:
T x{};
I also understand if T is a (non-POD before C++11) class and the following default initialization actually equals value initialization
T x;
Meanwhile, if direct initialization is not necessary, we can use copy initialization:
T x = T();
However, I think any of the three solutions have their limitation. I know if there are some arguments, I can also use an extra pair of parentheses:
T x((arg));
I want to adopt this strategy, but the following code does not work
T x(());
Are there are some better solutions with direct value initialization?
Use copy initialisation and rely on C++17's guarantee that copy elision will happen.
For example:
struct Foo
{
Foo() = default;
Foo(Foo const&) = delete;
};
int main()
{
auto f = Foo();
}
https://godbolt.org/g/9tbkjZ

How explicit must you be when calling a constructor?

I have this class
struct foo
{
explicit foo(const std::uint32_t& x, const std::uint32_t& y);
};
and a method
int main()
{
std::int32_t x = -1;
std::int32_t y = -1;
foo f(x, y);
}
On my compiler (MSVC2012), this compiles and runs with the values x and y wrapped around to unsigned types. I was not expecting this, but was expecting a compile error due to mismatched types.
What am I missing?
You're out of luck, the standard does allow implicit conversion of signed to unsigned via the creation of an anonymous temporary for an argument passed by constant reference.
(Note this is not true for a non-constant reference).
If you're using C++11, the best thing to do is to delete the constructor using
foo(const std::int32_t& x, const std::int32_t& y) = delete;
Pre C++11 you could make this constructor private and not define it. Rather like the old-fashioned not-copyable idioms.
MSVC2012 is a sort of half-way house C++03 / C++11 compiler. It implements some C++11 features but not others. Unfortunately deletion of constructors is one of the features it does not support so the privateisation approach is the best method available to you.
Actually, you should use the new brace-initialization syntax foo f{x, y} that will at least emit a warning. After that you can configure your compiler to treat warnings as errors and handle them accordingly, as good code should usually get rid of warnings too (because if you wanted the conversion to happen, you should have used an explicit cast).
explicit does not prevent implicit conversion with the constructor arguments (which clearly takes place here when binding the references); it prevents implicit construction.
void bar(foo);
int main()
{
foo f({0, 0}); // doesn't matter that the arguments are implicitly converted
bar({0, 0}); // error - implicit conversion required here to pass a foo
bar(f); // crucially, ok because argument requires no conv. construction
}

How does constructor conversion work in C++?

How does constructor conversion work?
#include <iostream>
using namespace::std;
class One {
public:
One() { cout<<"One"<<endl;}
};
class Two {
public:
Two(const One&) {cout<<"Two(const One&)"<<endl;}
};
void f(Two) {cout<<"f(Two)"<<endl;}
int main() {
One one;
f(one);
}
produces the output
One
Two(const One&)
f(Two)
Any constructor that can be called with a single argument is considered an implicit conversion constructor. This includes simple 1-argument cases, and usage of default arguments.
This conversion is considered in any context that wants X and provided Y, and Y has such implicit conversion possibility. Note that a plenty of other, built-in conversions also play as a mix (like adjusting const-ness, integral and fp promotions, conversions, etc.) The rule is that at most one "user defined" implicit conversion is allowed in the mix.
In some cases it may be quite surprising, so the general advice is to make any such ctors explicit. That keyword makes the conversion possible but not implicitly: you must use T() syntax to force it.
As an example consider std::vector that has a ctor taking size_t, setting the initial size. It is explicit -- otherwise your foo(vector<double> const& ) function could be mistakenly called with foo(42).
It's right result. Since constructor is not explicit - implicit conversion works (here One is implicitly converted to Two).
one is created, then when passed to f converted to Two.
What the Two(const One&) {cout<<"Two(const One&)"<<endl;} constructor means is that you're allowed to construct a Two value at any time - implicitly - from a One. When you call f(one) it wants a Two parameter, it's given a One, so the compiler puts 2 and 2 together and says "I'll make a temporary Two from the One and complete the call to f()"... everyone will be happy. Hurray!
Compiler has to create copy of Two instance on stack. When you call f() with argument which is object of class One (or any other) compiler looks to definition of class Two and tries to find constructor which takes One(or any other) object(or reference) as an argument. When such constructor has been found it constructs object using it. It's called implicit because compiler do it without your interference.
class Foo {
public:
Foo(int number) {cout<<"Foo(int number)"<<endl;}
};
void f(Foo) {cout<<"f(Foo)"<<endl;}
int main() {
f(24);
} ///:~
Output will be:
Foo(int number)
f(Foo)

Why double parameter constructor begins with an explicit keyword?

My buddy and I have been recently reading leveldb source code. And we encounter this problem. In leveldb db/skiplist.h file, there is a constructor declaration:
explicit SkipList(Comparator cmp, Arena* arena);
I know explicit constructor with single parameter means no implicit type conversion for constructor parameter. But what does double parameters constructor with explicit keyword mean?
Is it new rule of C++11?
Thanks.
With C++11, you can use braced-init-lists in place of some other expressions, and that makes a difference. For instance, you can use them in return statements:
SkipList foo() {
return {{}, nullptr}; //does not compile with explicit constructor
return SkipList{{}, nullptr}; //compiles with or without explicit constructor
}