Reputation: 271
I am actually writing an implementation of string and am facing a confusing scenario while trying to construct string from single character.
mystring.h
class string final {
private:
static constexpr std::size_t default_capacity_ = 0;
std::size_t current_capacity_;
std::size_t sz_;
std::unique_ptr<char[]> ptr_;
public:
explicit string(char); // [1]
string();
string(const string&);
string(string&&) noexcept;
string(const char*); // Undefined behavior if the input parameter is nullptr.
~string() noexcept;
};
mystring.cpp
string::string(char ch) {
sz_ = 1;
current_capacity_ = get_appropriate_capacity(sz_);
ptr_ = std::make_unique<char[]>(current_capacity_ + 1);
ptr_.get()[0] = ch;
ptr_.get()[1] = '\0';
}
string::string(const char* c_string) { // [2]
sz_ = std::strlen(c_string);
current_capacity_ = get_appropriate_capacity(sz_);
ptr_ = std::make_unique<char[]>(current_capacity_ + 1);
std::memcpy(ptr_.get(), c_string, sz_ + 1);
}
test.cpp
#include "my_string.h"
using namespace kapil;
int main() {
string z8 = 'c'; // [3]
return 0;
}
In this example, [3] doesn't compile as the constructor string(char ch)
for string is explicit. [3] gives the following error :
error: invalid conversion from ‘char’ to ‘const char*’ [-fpermissive] string z8 = 'c'; ^~~ In file included from test_string.cpp:1:0: my_string.h:22:7: note: initializing argument 1 of ‘kapil::string::string(const char*)’ string(const char*); // Undefined behavior if the input parameter is nullptr.
Making it non-explicit will allow the code to work, but it will also allow statements like below :
string s = 144; // [4]
I have following questions in this context :
[a] Is there a way, using 'explicit' constructor, to enable string s = 's';
but not string s = 144;
[b] The error caused due to [4] shows that it tries to match the constructor call with string(const char*)
, why is it so ? provided we have a constructor string(char ch)
.
[c] If there is no way to achieve [a] with 'explicit' constructor, then what is the (right) way to achieve it.
P.S. This code shows partial implementation. Kindly visit https://github.com/singhkapil2905/cplusplus-string-implementation to see complete implementation.
Thanks for any help :)
Upvotes: 1
Views: 51
Reputation: 63114
The compiler tries to match the string(char const *)
constructor simply because the other one is explicit
, and thus ignored in copy-initialization.
To allow copy-initialization from a char
, the first step is indeed to implement string(char)
as non-explicit
. Then what you need to prevent copy-initialization from an int
is to avoid the conversion to char
. You can do that simply by providing and deleting a constructor that is a better match:
string(int) = delete;
Note that in any case, string s('a');
works with an explicit
constructor as well since it is direct-initialization.
Upvotes: 5