Implicit conversion from char** to const char**
Such a conversion would allow you to put a const char*
into your array of char*
, which would be unsafe. In print
you could do:
thing[0] = "abc";
Now argv[0]
would point to a string literal that cannot be modified, while main
expects it to be non-const (char*
). So for type safety this conversion is not allowed.
Why C doesn't allow implicit conversion from char ** to const char *const * (and C++ does)?
C and C++ are different in this respect. I don't have an answer to why C++ is more generous, other than that the C++ behaviour seems to me to be correct.
C simply doesn't allow indirect const
conversion. That is a conservative, easy-to-implement restriction, with the unfortunate consequence that you cannot provide char*[]
to a function expecting char const* const*
. The restriction is in §6.3.2.3, paragraph 2, and it is simply not recursive:
For any qualifier
q
, a pointer to a non-q
-qualified type may be converted to a pointer to theq
-qualified version of the type; the values stored in the original and converted pointers shall compare equal.
C++ allows conversions according to a somewhat complex formulation in §4.4 [conv.qual], paragraph 3. It is permitted to convert
T cvn Pn-1cvn-1 … P1cv1 P0cv0
⇒T cv'n Pn-1cv'n-1 … P1cv'1 P0cv'0
(where T
is a type; P1…Pn
are pointer/array type constructors, and each cv0…cvn
is some possibly empty subset of const
and volatile
)
provided that:
For every
k > 0
,cvk
is a subset ofcv'k
(so you can't remove aconst
or avolatile
), andIf
cvk
andcv'k
differ for somek > 0
, all the followingcv'i>k
includeconst
.
In the actual standard, that expression is reversed; I put it in the order of declaration, whereas in the standard it is in order of application of the pointer/array constructors. I didn't change the direction of the numbering, though, which is why they are numbered right to left. I also left out some details -- for example, it's not strictly necessary for the two T
s to be identical -- but I think it gives an idea of the intention.
The explanation for the first restriction is reasonably obvious. The second restriction prevents the problem described in the C FAQ, where a const
pointer might be stored into a non-const
pointer object, and then subsequently used to mutate the const
object it points to.
The bottom line is that in C++, your prototype const char *const * param
will work with arguments of type char**
, const char**
, or even char*const*
, but in C only the last one will work without warning, and it is the least useful. The only workaround I know of (other than switching to C++) is to ignore the warning.
For what it's worth, there is a note in the Rationale section of the Posix specification of the exec*
interfaces about the problem this causes for these prototypes, and the workaround selected by Posix, which is to use char*[]
as the prototype and textually note that these are constant: (emphasis added)
The statement about
argv[]
andenvp[]
being constants is included to make explicit to future writers of language bindings that these objects are completely constant. Due to a limitation of the ISO C standard, it is not possible to state that idea in standard C. Specifying two levels ofconst
-qualification for theargv[]
andenvp[]
parameters for the exec functions may seem to be the natural choice, given that these functions do not modify either the array of pointers or the characters to which the function points, but this would disallow existing correct code. Instead, only the array of pointers is noted as constant.
There's a useful compatibility chart following that paragraph, which I didn't quote because of the formatting limitations of this site.
Why const char* implicitly converted to bool rather than std::string?
Because the implicit conversion from const char*
to bool
is qualified as standard conversion, while const char*
to std::string
is user-defined conversion. The former has higher ranking and wins in overload resolution.
A standard conversion sequence is always better than a user-defined conversion sequence or an ellipsis conversion sequence.
BTW: mystruct obj(c);
performs direct initialization, explicit
converting constructors including mystruct::mystruct(bool)
are considered too. As the result, c
is converted to bool
then passed to mystruct::mystruct(bool)
as argument to construct obj
.
Direct-initialization is more permissive than copy-initialization: copy-initialization only considers non-explicit constructors and non-explicit user-defined conversion functions, while direct-initialization considers all constructors and all user-defined conversion functions.
About explicit
specifier,
- Specifies that a constructor
or conversion function (since C++11)
or deduction guide (since C++17)
is explicit, that is, it cannot be used for implicit conversions and copy-initialization.
Explain: Converting 'char **' to 'const char **', Conversion loses qualifiers
Yes, you cannot implicitly convert from a T **
to a const T **
, because the compiler can no longer guarantee that the const-ness won't be violated.
Consider the following code (borrowed from the C FAQ question on exactly this topic: Why can't I pass a char **
to a function which expects a const char **
?):
const char c = 'x';
char *p1;
const char **p2 = &p1; // 3
*p2 = &c;
*p1 = 'X'; // 5
If the compiler allowed line 3, then line 5 would end up writing to a const
object.
Why is it not possible to implicitly convert char** to const char **
because if it was allowed then you could inadvertently change something that was declared const
.
here's a concrete abuse example, if the rules allowed this:
char const* s = "a literal, very const";
bar(const char** pp )
{
*pp = s;
}
foo(char** arr)
{
bar(arr);
char* unconsted_s = *arr;
unconsted_s[0] = 'X';
}
This is also a FAQ. It’s often a good idea to check the FAQ (or just google) before asking.
Why doesn't std::string provide implicit conversion to char*?
From the C++ Programming Language 20.3.7 (emphasis mine):
Conversion to a C-style string could have been provided by an operator const char*() rather than c_str(). This would have provided the convenience of an implicit conversion at the cost of surprises in cases in which such a conversion was unexpected.
Conversion from `const char[]` to non-scalar type requested
The problem is that two class-type conversions are required:
const char[6]
tostd::string
std::string
tofield<std::string>
.
There is a rule that implicit conversion can have at most one class-type conversion (the official term is "user-defined" conversion although this includes class types that are part of the standard library).
To fix it you can either use your suggested fix; or manually specify one of the conversions, e.g:
auto strB = field<std::string>("Hello");
field<std::string> strC = std::string("Hello");
field<std::string> strD = "Hello"s;
or you could add a constructor for const char[]
.
SFINAE version of char array constructor (there will be better ways in C++20 I'm sure):
template<size_t N, typename = std::enable_if_t<std::is_same_v<T, std::string>>>
field(char const (&t)[N])
: t_(std::make_unique<T>(t)) {}
Implicit conversion from char to int for constructors in C++
But C++ standard allows only 1 implicit conversion.
Thats not correct.
From cppreference:
Implicit conversion sequence consists of the following, in this order:
- zero or one standard conversion sequence;
- zero or one user-defined conversion;
- zero or one standard conversion sequence.
From the language point of view, const char[N]
-> std::string
(or const char*
to std::string
) is a user-defined conversion. Hence, the commented out lines are errors. On the other hand,
A obj_5 = ch; // How is this working?
is fine, because there is only a single user-defined conversion involved.
Invalid conversion from ‘const char*’ to ‘unsigned char*’
In C++ string literals have types of constant character arrays. For example string literal "123"
has type const char[4]
.
In expressions with rare exceptions arrays are converted to pointers to their first elements.
So in this declaration
unsigned char* t="123";
the initializer has type const char *
. There is no implicit conversion from const char *
to unsigned char *
You could write
const unsigned char* t = reinterpret_cast<const unsigned char *>( "123" );
Warning about using explicit keyword in a conversion operator
I can think of one unintentional implicit conversion here. If you were to accidentally write
Date date;
// ...
if (date) { /* ... */ }
the compiler could first convert date
to const char*
, and then const char*
to bool
, and this would be a difficult-to-debug situation. The explicit
operator protects against this situation.
There's a better way to define how your class should be printed to std::cout
:
class Date {
// ...
std::string toString() const {
// ...
return formattedDate.str();
}
}
std::ostream& operator<<(std::ostream& out, const Date& date) {
return out << date.toString();
}
If you must use a conversion operator, why not make it explicit and convert where needed? It would be easier to see from the code exactly what is happening.
std::cout << static_cast<const char*>(date);
Related Topics
Pure Virtual Functions May Not Have an Inline Definition. Why
What's the Difference Between Long Long and Long
Why Is Std::Min Failing When Windows.H Is Included
C++ Lambdas How to Capture Variadic Parameter Pack from the Upper Scope
Simplest Way to Determine Return Type of Function
How to Get Function Name Inside a C++ Function
Default Argument in the Middle of Parameter List
Launch Failed. Binary Not Found. Cdt on Eclipse Helios
Conversion Function for Error Checking Considered Good
How to Connect MySQL Database Using C++
How to Make This C++ Object Non-Copyable
When to Use Std::Begin and Std::End Instead of Container Specific Versions
What Are the Use Cases for Having a Function Return by Const Value for Non-Builtin Type
How Much Footprint Does C++ Exception Handling Add
How to Construct a Std::String from a Std::Vector<Char>
Are Pointer Variables Just Integers with Some Operators or Are They "Symbolic"
Scope VS Life of Variable in C
Calling Initializer_List Constructor via Make_Unique/Make_Shared