I am trying to implement a hack where I am trying to overload return. I will let the code talk.
namespace tcn
{
class foo
{
std::string blah;
public:
class proxy
{
int intval;
std::string strval;
public:
proxy(int intv, std::string strv) : intval(intv), strval(strv) {};
operator int() const { return intval; }
operator std::string() const { return strval; }
};
foo();
~foo();
proxy get();
};
foo::foo()
{
// Create stuff //
}
foo::~foo()
{
// Destroy stuff //
}
foo::proxy foo::get()
{
int intval = 911;
std::string strval = "Hello!?";
proxy temp(intval, strval);
return temp;
}
}
int main()
{
tcn::foo bar;
std::string ts = bar.get(); // OK
int ti = bar.get(); // OK
ti = bar.get(); // OK
ts = bar.get(); // Compile error here
return 0;
}
If I try to compile the code it gives an error like following
error: ambiguous overload for 'operator=' (operand types are
'std::string {aka std::basic_string}' and 'tcn::foo::proxy')
ts = bar.get();
I was wondering how to overcome this. I have seen other ways to implement this by using 'hints' ,But am trying to give an easy interface to the user. So I am looking for a simple assignment from the user side. How else could this be implemented?
Thank you in advance and if this looks lame- I apologize. I am no that good in C++.
The call is ambiguous because std::string::operator= has overloads taking std::string and char. Both of these can be called using a tcn::proxy: the first using the std::string conversion operator, and the second using the int conversion operator followed by an integral conversion.
Usually overload resolution would prefer the implicit conversion sequence with no necessary standard conversions over the one requiring an integral conversion, but this choice is only considered if the two conversion sequences go through the same function. Since you have two separate paths going through two different functions, the call is ambiguous.
The solution is to not use integral conversions for things like that; it just leads to weird edge cases, surprising behaviour and hidden bugs.
Related
Consider this simple example:
template <class Type>
class smartref {
public:
smartref() : data(new Type) { }
operator Type&(){ return *data; }
private:
Type* data;
};
class person {
public:
void think() { std::cout << "I am thinking"; }
};
int main() {
smartref<person> p;
p.think(); // why does not the compiler try substituting Type&?
}
How do conversion operators work in C++? (i.e) when does the compiler try substituting the type defined after the conversion operator?
Some random situations where conversion functions are used and not used follow.
First, note that conversion functions are never used to convert to the same class type or to a base class type.
Conversion during argument passing
Conversion during argument passing will use the rules for copy initialization. These rules just consider any conversion function, disregarding of whether converting to a reference or not.
struct B { };
struct A {
operator B() { return B(); }
};
void f(B);
int main() { f(A()); } // called!
Argument passing is just one context of copy initialization. Another is the "pure" form using the copy initialization syntax
B b = A(); // called!
Conversion to reference
In the conditional operator, conversion to a reference type is possible, if the type converted to is an lvalue.
struct B { };
struct A {
operator B&() { static B b; return b; }
};
int main() { B b; 0 ? b : A(); } // called!
Another conversion to reference is when you bind a reference, directly
struct B { };
struct A {
operator B&() { static B b; return b; }
};
B &b = A(); // called!
Conversion to function pointers
You may have a conversion function to a function pointer or reference, and when a call is made, then it might be used.
typedef void (*fPtr)(int);
void foo(int a);
struct test {
operator fPtr() { return foo; }
};
int main() {
test t; t(10); // called!
}
This thing can actually become quite useful sometimes.
Conversion to non class types
The implicit conversions that happen always and everywhere can use user defined conversions too. You may define a conversion function that returns a boolean value
struct test {
operator bool() { return true; }
};
int main() {
test t;
if(t) { ... }
}
(The conversion to bool in this case can be made safer by the safe-bool idiom, to forbid conversions to other integer types.) The conversions are triggered anywhere where a built-in operator expects a certain type. Conversions may get into the way, though.
struct test {
void operator[](unsigned int) { }
operator char *() { static char c; return &c; }
};
int main() {
test t; t[0]; // ambiguous
}
// (t).operator[] (unsigned int) : member
// operator[](T *, std::ptrdiff_t) : built-in
The call can be ambiguous, because for the member, the second parameter needs a conversion, and for the built-in operator, the first needs a user defined conversion. The other two parameters match perfectly respectively. The call can be non-ambiguous in some cases (ptrdiff_t needs be different from int then).
Conversion function template
Templates allow some nice things, but better be very cautious about them. The following makes a type convertible to any pointer type (member pointers aren't seen as "pointer types").
struct test {
template<typename T>
operator T*() { return 0; }
};
void *pv = test();
bool *pb = test();
The "." operator is not overloadable in C++. And whenever you say x.y, no conversion will automatically be be performed on x.
Conversions aren't magic. Just because A has a conversion to B and B has a foo method doesn't mean that a.foo() will call B::foo().
The compiler tries to use a conversion in four situations
You explicitly cast a variable to another type
You pass the variable as an argument to a function that expects a different type in that position (operators count as functions here)
You assign the variable to a variable of a different type
You use the variable copy-construct or initialize a variable of a different type
There are three types of conversions, other than those involved with inheritance
Built-in conversions (e.g. int-to-double)
Implicit construction, where class B defines a constructor taking a single argument of type A, and does not mark it with the "explicit" keyword
User-defined conversion operators, where class A defines an operator B (as in your example)
How the compiler decides which type of conversion to use and when (especially when there are multiple choices) is pretty involved, and I'd do a bad job of trying to condense it into an answer on SO. Section 12.3 of the C++ standard discusses implicit construction and user-defined conversion operators.
(There may be some conversion situations or methods that I haven't thought of, so please comment or edit them if you see something missing)
Implicit conversion (whether by conversion operators or non-explicit constructors) occurs when passing parameters to functions (including overloaded and default operators for classes). In addition to this, there are some implicit conversions performed on arithmetic types (so adding a char and a long results in the addition of two longs, with a long result).
Implicit conversion does not apply to the object on which a member function call is made: for the purposes of implicit conversion, "this" is not a function parameter.
The compiler will attempt one(!) user-defined cast (implicit ctor or cast operator) if you try to use an object (reference) of type T where U is required.
The . operator, however, will always try to access a member of the object (reference) on its left side. That's just the way it's defined. If you want something more fancy, that's what operator->() can be overloaded for.
You should do
((person)p).think();
The compiler doesn't have the information for automatically casting to person, so you need explicit casting.
If you would use something like
person pers = p;
Then the compiler has information for implicit casting to person.
You can have "casting" through constructors:
class A
{
public:
A( int );
};
A a = 10; // Looks like a cast from int to A
These are some brief examples. Casting (implicit, explicit, etc) needs more to explain. You can find details in serious C++ books (see the questions about C++ books on stack overflow for good titles, like this one).
//Virtual table Fuction(VFT)
#include <iostream>
using namespace std;
class smartref {
public:
virtual char think() { }//for Late bindig make virtual function if not make virtual function of char think() {} then become early binding and pointer call this class function
smartref() : data(new char) { }
operator char(){ return *data; }
private:
char* data;
};
class person:public smartref
{
public:
char think() { std::cout << "I am thinking"; }
};
int main() {
smartref *p;//make pointer of class
person o1;//make object of class
p=&o1;//store object address in pointer
p->think(); // Late Binding in class person
return 0;
}
In the class below,
Why would you make the operators explicit. I thought that explicit was to prevent implicit calling of constructors?
class Content
{
public:
virtual ~Content() = 0;
virtual explicit operator float&();
virtual explicit operator long long&();
virtual explicit operator std::string&()
}
I thought that explicit was to prevent implicit calling of
constructors?
Since C++11 it also applies to user-defined conversions (a.k.a. the cast operator).
Why would you make the operators explicit
Used in this context, the explicit keyword makes the conversion eligible only for direct-initialization and explicit conversions. See here under [class.conv.fct¶2]:
A conversion function may be explicit ([dcl.fct.spec]), in which case
it is only considered as a user-defined conversion for
direct-initialization ([dcl.init]). Otherwise, user-defined
conversions are not restricted to use in assignments and
initializations.
This aids you in making sure the compiler doesn't try the conversion against your intention, so that you have to explicitly cast it yourself, leaving less room for error. Example:
struct Foo
{
explicit operator int() {return 0;}
operator int*() {return nullptr;}
};
int main()
{
Foo foo;
//int xi = foo; // Error, conversion must be explicit
int i = static_cast<int>(foo); // OK, conversion is explicit
int* i_ptr = foo; // OK, implicit conversion to `int*` is allowed
int i_direct(foo); // OK, direct initialization allowed
int* i_ptr_direct(foo); // OK, direct initialization after implicit conversion
return 0;
}
It can also help resolve ambiguity in cases where multiple conversion options apply, leaving the compiler without a criteria for deciding which one to choose:
struct Bar
{
operator int() {return 1;}
operator char() {return '1';}
};
int main()
{
Bar bar;
//double d = bar; // Error, implicit conversion is ambiguous
return 0;
}
Add explicit:
struct Bar
{
operator int() {return 1;}
explicit operator char() {return '1';}
};
int main()
{
Bar bar;
double d = bar; // OK, implicit conversion to `int` is the only option
return 0;
}
Consider the following:
struct Content
{
operator float() { return 42.f; }
friend Content operator+(Content& lhs, float) { return lhs; }
};
int main()
{
Content c{};
c + 0; // error: ambiguous overload for 'operator+'
}
Here, the compiler cannot choose between operator+(Content&, float) and operator+(float, int). Making the float operator explicit resolves this ambiguity*:
c + 0; // operator+(Content&, float)
or
static_cast<float>(c) + 0; // operator+(float, int)
*) provided it makes sense to prefer one over the other.
The other answers cover how it works, but I think you should be told why it was added to C++.
A smart pointer usually has a conversion to bool so you can do this:
std::shared_ptr<int> foo;
if (foo) {
*foo = 7;
}
where if(foo) converts foo to bool. Unfortunately:
int x = foo+2;
converts foo to bool, then to int, then adds 2. This is almost always a bug. This is permitted because while only one user defined conversion is done, a user defined conversion followed by a built in conversion can silently occur.
To fix this programmers would do crazy things like add:
struct secret {
void unused();
};
struct smart_ptr {
using secret_mem_ptr = void(secret::*)();
operator secret_mem_ptr() const { return 0; }
};
and secret_mem_ptr is a secret pointer to member. A pointer to member has a built in conversion to bool, so:
smart_ptr ptr;
if (!ptr) {
}
"works" -- ptr is convert to secret_mem_ptr, which then is convered to bool, which is then used to decide which branch to take.
This was more than a bit of a hack.
They added explicit on conversion operators to solve this exact problem.
Now:
struct smart_ptr {
explicit operator bool() const { return true; }
};
doesn't permit:
smart_ptr ptr;
int x = 3 + ptr;
but it does permit:
if (ptr) {
}
because the rules were hand-crafted to support exactly that use case. It also doesn't permit:
bool test() {
smart_ptr ptr;
return ptr;
}
here, you have to type:
bool test() {
smart_ptr ptr;
return (bool)ptr;
}
where you explicitly convert ptr to bool.
(I am usually really against C-style casts; I make an exception in the case of (bool)).
You would use it if you wanted a Content object never to be implicitly converted to (say) a float. This could happen in the following way:
void f( float f );
....
Content c;
f( c ); // conversion from Content to float
Without the explicit qualifier, the conversion happens implicitly; with it, you get a compilation error.
Silent, implicit conversions can be the source of a lot of confusion and/or bugs, so it's generally better to make the operators explicit , or probably better yet to provide named functions, such as ToFloat, which tell the reader exactly what is going on.
Consider this simple example:
template <class Type>
class smartref {
public:
smartref() : data(new Type) { }
operator Type&(){ return *data; }
private:
Type* data;
};
class person {
public:
void think() { std::cout << "I am thinking"; }
};
int main() {
smartref<person> p;
p.think(); // why does not the compiler try substituting Type&?
}
How do conversion operators work in C++? (i.e) when does the compiler try substituting the type defined after the conversion operator?
Some random situations where conversion functions are used and not used follow.
First, note that conversion functions are never used to convert to the same class type or to a base class type.
Conversion during argument passing
Conversion during argument passing will use the rules for copy initialization. These rules just consider any conversion function, disregarding of whether converting to a reference or not.
struct B { };
struct A {
operator B() { return B(); }
};
void f(B);
int main() { f(A()); } // called!
Argument passing is just one context of copy initialization. Another is the "pure" form using the copy initialization syntax
B b = A(); // called!
Conversion to reference
In the conditional operator, conversion to a reference type is possible, if the type converted to is an lvalue.
struct B { };
struct A {
operator B&() { static B b; return b; }
};
int main() { B b; 0 ? b : A(); } // called!
Another conversion to reference is when you bind a reference, directly
struct B { };
struct A {
operator B&() { static B b; return b; }
};
B &b = A(); // called!
Conversion to function pointers
You may have a conversion function to a function pointer or reference, and when a call is made, then it might be used.
typedef void (*fPtr)(int);
void foo(int a);
struct test {
operator fPtr() { return foo; }
};
int main() {
test t; t(10); // called!
}
This thing can actually become quite useful sometimes.
Conversion to non class types
The implicit conversions that happen always and everywhere can use user defined conversions too. You may define a conversion function that returns a boolean value
struct test {
operator bool() { return true; }
};
int main() {
test t;
if(t) { ... }
}
(The conversion to bool in this case can be made safer by the safe-bool idiom, to forbid conversions to other integer types.) The conversions are triggered anywhere where a built-in operator expects a certain type. Conversions may get into the way, though.
struct test {
void operator[](unsigned int) { }
operator char *() { static char c; return &c; }
};
int main() {
test t; t[0]; // ambiguous
}
// (t).operator[] (unsigned int) : member
// operator[](T *, std::ptrdiff_t) : built-in
The call can be ambiguous, because for the member, the second parameter needs a conversion, and for the built-in operator, the first needs a user defined conversion. The other two parameters match perfectly respectively. The call can be non-ambiguous in some cases (ptrdiff_t needs be different from int then).
Conversion function template
Templates allow some nice things, but better be very cautious about them. The following makes a type convertible to any pointer type (member pointers aren't seen as "pointer types").
struct test {
template<typename T>
operator T*() { return 0; }
};
void *pv = test();
bool *pb = test();
The "." operator is not overloadable in C++. And whenever you say x.y, no conversion will automatically be be performed on x.
Conversions aren't magic. Just because A has a conversion to B and B has a foo method doesn't mean that a.foo() will call B::foo().
The compiler tries to use a conversion in four situations
You explicitly cast a variable to another type
You pass the variable as an argument to a function that expects a different type in that position (operators count as functions here)
You assign the variable to a variable of a different type
You use the variable copy-construct or initialize a variable of a different type
There are three types of conversions, other than those involved with inheritance
Built-in conversions (e.g. int-to-double)
Implicit construction, where class B defines a constructor taking a single argument of type A, and does not mark it with the "explicit" keyword
User-defined conversion operators, where class A defines an operator B (as in your example)
How the compiler decides which type of conversion to use and when (especially when there are multiple choices) is pretty involved, and I'd do a bad job of trying to condense it into an answer on SO. Section 12.3 of the C++ standard discusses implicit construction and user-defined conversion operators.
(There may be some conversion situations or methods that I haven't thought of, so please comment or edit them if you see something missing)
Implicit conversion (whether by conversion operators or non-explicit constructors) occurs when passing parameters to functions (including overloaded and default operators for classes). In addition to this, there are some implicit conversions performed on arithmetic types (so adding a char and a long results in the addition of two longs, with a long result).
Implicit conversion does not apply to the object on which a member function call is made: for the purposes of implicit conversion, "this" is not a function parameter.
The compiler will attempt one(!) user-defined cast (implicit ctor or cast operator) if you try to use an object (reference) of type T where U is required.
The . operator, however, will always try to access a member of the object (reference) on its left side. That's just the way it's defined. If you want something more fancy, that's what operator->() can be overloaded for.
You should do
((person)p).think();
The compiler doesn't have the information for automatically casting to person, so you need explicit casting.
If you would use something like
person pers = p;
Then the compiler has information for implicit casting to person.
You can have "casting" through constructors:
class A
{
public:
A( int );
};
A a = 10; // Looks like a cast from int to A
These are some brief examples. Casting (implicit, explicit, etc) needs more to explain. You can find details in serious C++ books (see the questions about C++ books on stack overflow for good titles, like this one).
//Virtual table Fuction(VFT)
#include <iostream>
using namespace std;
class smartref {
public:
virtual char think() { }//for Late bindig make virtual function if not make virtual function of char think() {} then become early binding and pointer call this class function
smartref() : data(new char) { }
operator char(){ return *data; }
private:
char* data;
};
class person:public smartref
{
public:
char think() { std::cout << "I am thinking"; }
};
int main() {
smartref *p;//make pointer of class
person o1;//make object of class
p=&o1;//store object address in pointer
p->think(); // Late Binding in class person
return 0;
}
'int' and 'double' conversion functions is 'explicit' and in this code why have I permit for use this conversion instead of error message?
If I delete all my conversion overload functions code occur 'conversion error'
class Person
{
public:
Person(string s = "", int age = 0) :Name(s), Age(age) {}
operator string() const { return Name; }
explicit operator int() const{ return 10; } // ! Explicit
explicit operator double()const { return 20; } //! Explicit
operator bool()const { if (Name != "") return true; return false; } // using this
};
int main(){
Person a;
int z = a;
std::cout << z << std::endl; // Why print "1"? Why uses bool conversion?
}
I this it is answer:
Because 'a' can not be convert to int or double it occur error, but because it has bool conversion function, which can convert to int and int to double, code use this function.
int z = a;
Looks innocuous, right?
Well, the above line calls the implicit bool-conversion-operator, because that's the only way you left it to get from Person to int, and that only needs one user-defined conversion (the maximum allowed).
This is the reason for the safe-bool-idiom before C++11, and the major reason for the general advice to mark conversion operators and single-argument ctors explicit unless they are not transformative nor lossy.
If you want to see it for yourself, fix your code and trace invocation of your operator bool.
Consider the following class which contains a conversion function for the std::string type:
class SomeType
{
public:
SomeType(char *value)
{
_str = value;
}
operator std::string()
{
return std::string(_str);
}
private:
char *_str;
};
The following snippet fails to compile with the error: no operator "==" matches these operands
int main(int argc, char* argv[])
{
SomeType a("test");
if (a == std::string("test")) // ERROR on this line
{
int debug = 1;
}
return 0;
}
I realize I could define an operator== method that accepts std::string operand, but why doesn't the conversion function work?
The problem is that std::string is in fact a template and as such I imagine that it's comparison operator is also a template. And in that case the standard as I recall states that no implicit conversion will happen for the required arguments, which means you'd have to cast SomeType to string yourself for it to be called.
As stated in Item 46 of Effective C++:
[...], because implicit type conversions are never considered during template argument deduction. Never. Such conversions are used during function calls, yes, but before you can call a function, you have to know which functions exist. [...]
You can find more info here.
std::string is actually typedef to std::basic_string<char, i_do_not_remember>
There no operator == that get just std::string It's template one
template<...>
bool operator (basic_string<...>& a, basic_string<...>& b) {
//
}
But template types can't be deduced here. You may cast it manually:
if (static_cast<std::string>(a) == std::string("test"))