According to en.cppreference.com in convertible_to:
The concept convertible_to<From, To> specifies that an expression of the same type and value category as those of std::declval() can be implicitly and explicitly converted to the type To, and the two forms of conversion are equivalent.
I Understood this to mean that convertible_to
concept will identify convertible_to<U, V>
as satisfied if U
has a member explicit operator V()
. Even if the operator is explicit and not an implicit operator.
However I have discovered that this is not the case in msvc.
The following code fails to compile due to the static assert:
#include <concepts>
#include <iostream>
class ExplictClass
{
public:
inline explicit operator int() const
{
return 5;
}
};
int main()
{
static_assert(std::convertible_to<ExplictClass, int>, "Explicit not convertible?"); // Fails here, concept not satisfied.
}
Is this a misunderstanding I have about the concept std::convertible_to
, an error in the code, or error in en.cppreference.com, or Non-conformance of msvc v19.
Attached link to compiler explorer with above code using x64 msvc v19.latest
EDIT:
The actual need for convertible_to
was to generate a to_string
function template that works well with castable types declared as so:
template<class T>
std::string to_string(T val)
{
std::ostringstream stream;
stream << val;
return stream.str();
}
template<Convertible<std::string> T>
std::string to_string(T val)
{
return static_cast<std::string>(val);
}
Here I want types like const char*
, char*
, a type like ExplicitClass
(with explicit operator std::string
) all to use the second method, with the first method being a fallback option
std::convertible_to
requires both implicit and explicit conversion1). This can be seen in the definition:1) Note: implicit convertibility almost always implies explicit convertibility
Your
ExplicitClass
only has an explicit conversion toint
, meaning that you can writeExplicitClass(0)
, but it would not be possible to writeExplicitClass e = 0;
, which requires an implicit conversion.If you want a concept which tests whether
ExplicitClass
can be explicitly converted toint
, you have two options:A - Use just the explicit part of
std::convertible_to
B: Use
std::constructible_from
Note that
std::constructible_from<To, From>
will test whether:std::is_nothrow_destructible_v<To>
, andTo obj(From)
is well-formed, which is a weaker form ofstatic_cast<To>(From)
(both are direct initializaton, but onlystatic_cast
can downcast pointers fromBase*
toDerived*
, among other differences)This means that
std::constructible_from
isn't equivalent to astatic_cast
, but it will do exactly what you want for class types likeExplicitClass
.