Question:
The std::bitset
has several constructors. One of them (3) looks like:
template< class CharT, class Traits, class Alloc >
explicit bitset( const std::basic_string<CharT,Traits,Alloc>& str,
typename std::basic_string<CharT,Traits,Alloc>::size_type pos = 0,
typename std::basic_string<CharT,Traits,Alloc>::size_type n =
std::basic_string<CharT,Traits,Alloc>::npos,
CharT zero = CharT('0'),
CharT one = CharT('1'));
Other (4):
template< class CharT >
explicit bitset( const CharT* str,
typename std::basic_string<CharT>::size_type n =
std::basic_string<CharT>::npos,
CharT zero = CharT('0'),
CharT one = CharT('1'));
Why do we need a constructor (4) when there is (3)?
And in particular, why use CharT*
instead std::basic_string
?
Answer:
I think this has to do with the inclusion of a new feature in the C++ standard as an argument to use an initialization list in curly braces.
The point is that all class constructors are declared with an explicit
function specifier to prevent implicit conversion of objects of other types to class objects.
In this case, if you call the class constructor with an argument in curly braces with one type, then there will be no conversion of initialization list objects to another type.
Compare these two demo programs
#include <iostream>
#include <string>
struct A
{
explicit A( const std::string & ) {}
};
int main()
{
A a( "HEllo" );
return 0;
}
This program will compile successfully. A constructor argument from a literal type is converted to the type of a std::string
class object.
Now enclose the constructor call argument in curly braces
#include <iostream>
#include <string>
struct A
{
explicit A( const std::string & ) {}
};
int main()
{
A a( { "HEllo" } );
return 0;
}
This program will no longer compile.
Therefore, if you include another constructor with the explicit
specifier, the program will already compile
#include <iostream>
#include <string>
struct A
{
explicit A( const std::string & ) {}
explicit A( const char * ) {}
};
int main()
{
A a( { "HEllo" } );
return 0;
}