Overload resolution failure when streaming object via implicit conversion to string
14.8.1/4 in C++98
Implicit conversions (clause 4) will be performed on a function argument to convert it to the type of the corresponding function parameter if the parameter type contains no template-parameters that participate in template argument deduction.
Here you would like an instantiation of
template <class charT, class traits, class Allocator>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>&,
const basic_string<charT, traits, Allocator>&);
to be deduced without providing explicitly any template arguments. So all of the arguments contain a template-parameter that participates in the template argument deduction and thus none of them can get its value from an implicit conversion.
Implicit conversion to std::string
operator<<(std::basic_ostream&, std::basic_string)
is a function template and user defined conversions are not considered during template argument deduction. You need to overload operator<<
for your class.
Another option, of course, is a cast
std::cout << static_cast<std::string>(test);
Why does outputting a class with a conversion operator not work for std::string?
That operator is a free template
function. User defined conversions do not get checked when matching against a template
function arguments, it instead uses type pattern matching (substitution).
In theory a SFINAE overload using std::is_convertable<>
would be able to do what you want, but that technique was not used when operator<<
that outputs a std::string
to a basic_ostream<char>
was defined.
A manual overload to output your class to basic_ostream<...>
will fix your problem.
I would do this:
struct String {
std::string s;
operator std::string() const {return s;}
friend std::ostream& operator<<( std::ostream& os, String const& self) {
return os<<self.s;
}
};
which has the added benefit of not creating a wasted copy.
Implicit Conversion Operator for Class Objects to Strings
First of all, I think you're not using std::string value
as intended. This causes another compile error (at least on gcc 10.2).
It seems like you want a string and you're using a pointer to a string.
This can be fixed by replace string* value
with string value
, operator string&()
with operator string()
and *value = "YIKERS'
with value = "YIKERS"
. For the last one you might also want to check initializer lists.
Regarding the current compile error:
The compile error is caused by the code cout << abc
trying to use operator<< on an abc
which is an object of type A
. However, you did not overload this operator.
In your example this could be something like
friend std::ostream &operator<<(std::ostream &output, const A &a )
{
output << a.value;
return output;
}
Even if you have a user-defined conversion to std::string
you would still get compile time errors. This link explains it better than I think I could Why cannot use cout with user-defined conversion to std::string?
This is how I understand the explanation from link above:
string
header defines the following overload for operator<<
for std::basic_ostream
:
template <class CharT, class Traits, class Allocator>
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os,
const std::basic_string<CharT, Traits, Allocator>& str);
Also, std::string
is actually a typedef for std::basic_string<char>
.
However, if the conversion is implicit the following rule kicks in:
Type deduction does not consider implicit conversions (other than type
adjustments listed above): that's the job for overload resolution,
which happens later.
So, the compiler cannot deduce the second parameter for the function (e.g. const std::basic_string<CharT, Traits, Allocator>& str
) from A
. It can, however, deduce it for string
so you can explicitly convert abc
to string
like static_cast<string>(abc)
and that would work.
Error when using operator with implicitly converted non-fundamental data types
The stream operators for std::complex
are template functions. They will not be invoked unless you actual have a std::complex
as no conversions happens in template argument deduction. This means the compiler will not find a suitable overload to print a A<std::complex<int>>
You're first case for works because std::basic_ostream::operator <<
is overloaded to take an int
and you are allowed one user defined conversion is overload resolution.
As a work arround you can define your own operator <<
that takes your wrapper and forward to the underlying types' operator <<
. That would look like
template<typename T>
std::ostream& operator <<(std::ostream& os, const A<T>& a)
{
return os << static_cast<T>(a);
}
Forcing C++ to prefer an overload with an implicit conversion over a template
If you want to change the overloads such that the former overload is chosen whenever there is an implicit conversion possible, with the latter being the backup, you can do this with SFINAE via std::enable_if
:
#include <type_traits>
void call_function(const std::function<void()>& function)
{
std::cout << "CALL FUNCTION 1" << std::endl;
function();
}
template <typename Function,
// Consider this overload only if...
typename std::enable_if<
// the type cannot be converted to a std::function<void()>
!std::is_convertible<const Function&, std::function<void()>>::value,
int>::type = 0>
void call_function(const Function& function)
{
std::cout << "CALL FUNCTION 2" << std::endl;
function();
}
Demo
Alternatively, if you want to be able to support an unknown number of overloads of call_function
with the "CALL FUNCTION 2"
being a backup overload in case none of the functions work, you can do this too, but it requires quite a bit more work:
// Rename the functions to `call_function_impl`
void call_function_impl(const std::function<void()>& function)
{
std::cout << "CALL FUNCTION 1" << std::endl;
function();
}
void call_function_impl(const std::function<void(int, int)>& function)
{
std::cout << "CALL FUNCTION 2" << std::endl;
function(1, 2);
}
// The backup function must have a distinct name
template <typename Function>
void call_function_backup_impl(const Function& function)
{
std::cout << "CALL FUNCTION backup" << std::endl;
function();
}
// Implement std::void_t from C++17
template <typename>
struct void_impl {
using type = void;
};
template <typename T>
using void_t = typename void_impl<T>::type;
// Make a type trait to detect if the call_function_impl(...) call works
template <typename Function, typename = void>
struct has_call_function_impl
: std::false_type
{};
template <typename Function>
struct has_call_function_impl<Function,
void_t<decltype(call_function_impl(std::declval<const Function&>()))>>
: std::true_type
{};
// If the call_function_impl(...) call works, use it
template <typename Function,
typename std::enable_if<
has_call_function_impl<Function>::value,
int>::type = 0>
void call_function(const Function& function)
{
call_function_impl(function);
}
// Otherwise, fall back to the backup implementation
template <typename Function,
typename std::enable_if<
!has_call_function_impl<Function>::value,
int>::type = 0>
void call_function(const Function& function)
{
call_function_backup_impl(function);
}
Demo
Why does cout hello choose the non-member version of the operator ?
Why isn't there a member
operator<<
for thecout
object which takes aconst char[]
?
Character strings are handled separately. Creating member operators for std::basic_string
would require all streams to have a dependancy on std::basic_string
functionality, which is not always desirable. All of the member operators are for built-in language types, but std::basic_string
is a class instead, so it has non-member operator overloads. One could argue that const char[]
(which decays to const char*
) is a built-in type, but operator<<
streams const char*
similarly to std::basic_string
, and it doesn't make sense to split those implementations in two different areas of the library. Functionality for handling character strings, whether using arrays or classes, are usually grouped together.
Why isn't there a non-member operator<< which takes an integer?
Because there doesn't need to be one. It already exists as a member operator. You are not supposed to call member operators directly (unless you need to, which your example does not). You are supposed to just use the operator normally (stream << ...
) and let overload resolution pick the correct member or non-member operator, based on parameters, scoping, etc. If you think about it, a non-member overload would cause an ambiquity error. Should stream << 123
call stream.operator<<(123)
or ::operator<<(stream, 123)
? There can be only one choice, or the compile fails.
Why does
cout << “hello”
choose the non-member version of theoperator<<
?
Maybe because there is a particular non-memberoperator<<
overload which is a good candidate for aconst char[]
, rather than the member-operator<<
overload which takes avoid*
?
That is exactly why. A typed const char[]
parameter is a better match for a narrow string literal then an untyped void*
pointer. So, if both operators are in scope (and the const char[]
overload is only in scope if you use #include <string>
), then the compiler will choose the better matching overload.
Related Topics
What's a Very Easy C++ Profiler (Vc++)
Visual Studio 2015 "Non-Standard Syntax; Use '&' to Create a Pointer to Member"
C++ Erase Vector Element by Value Rather Than by Position
Std::Next_Permutation Implementation Explanation
Direct Way of Computing Clockwise Angle Between 2 Vectors
Vector of Vectors to Create Matrix
How to Detect C++11 Support of a Compiler With Cmake
"X Does Not Name a Type" Error in C++
How Do Conversion Operators Work in C++
What Are the Best (Portable) Cross-Platform Arbitrary-Precision Math Libraries
Pinpointing "Conditional Jump or Move Depends on Uninitialized Value(S)" Valgrind Message
Why Is ++I Considered an L-Value, But I++ Is Not
C++11 Features in Visual Studio 2012
Where Do "Pure Virtual Function Call" Crashes Come From
How to Pass a Reference to a Two-Dimensional Array to a Function