I have a wrapper class and I want to modify the data and convert it back to its original type.
class A
{
public:
A ( unsigned __int64 _a ) : a (_a)
{
}
operator unsigned __int64 () const
{
return a;
}
unsigned __int64 a;
};
I want the object of this class to implicitly convert back to unsigned __int64, but it failed.
Say,
A a( 0x100ull );
unsigned __int64 b = (a >> 16); // Error
Compiler gives C2678 error, no operator found or there is no acceptable conversion.
It seems this function operator unsigned __int64 () const doesn't work.
To be more specific, compiler says there is no acceptable conversion. I cannot accept the complain, because I have already given a good one. Can someone legitimize it?
It doesn't work because you haven't created an operator>> overload for your class that takes an integer and does something with it.
I'm guessing you're trying to do a right shift on your int, but I'm not sure that overloading your operator>> is a good idea for that, as these operators in a context like that, are normally used for streaming. It might confuse a reader or maintainer of your code afterwards.
See here for more info on operator overloading
Perhaps rethink your implementation strategy?
Related
I was trying to understand the usage of explicit keyword in c++ and looked at this question on SO
What does the explicit keyword mean in C++?
However, examples listed there (actually both top two answers) are not very clear regarding the usage. For example,
// classes example
#include <iostream>
using namespace std;
class String {
public:
explicit String(int n); // allocate n bytes to the String object
String(const char *p); // initializes object with char *p
};
String::String(int n)
{
cout<<"Entered int section";
}
String::String(const char *p)
{
cout<<"Entered char section";
}
int main () {
String mystring('x');
return 0;
}
Now I have declared String constructor as explicit, but lets say if I dont list it as explicit, if I call the constructor as,
String mystring('x');
OR
String mystring = 'x';
In both cases, I will enter the int section. Until and unless I specify the type of value, it defaults to int. Even if i get more specific with arguments, like declare one as int, other as double, and not use explicit with constructor name and call it this way
String mystring(2.5);
Or this way
String mystring = 2.5;
It will always default to the constructor with double as argument. So, I am having hard time understanding the real usage of explicit. Can you provide me an example where not using explicit will be a real failure?
explicit is intended to prevent implicit conversions. Anytime you use something like String(foo);, that's an explicit conversion, so using explicit won't change whether it succeeds or fails.
Therefore, let's look at a scenario that does involve implicit conversion. Let's start with your String class:
class String {
public:
explicit String(int n); // allocate n bytes to the String object
String(const char *p); // initializes object with char *p
};
Then let's define a function that receives a parameter of type String (could also be String const &, but String will do for the moment):
int f(String);
Your constructors allow implicit conversion from char const *, but only explicit conversion from int. This means if I call:
f("this is a string");
...the compiler will generate the code to construct a String object from the string literal, and then call f with that String object.
If, however, you attempt to call:
f(2);
It will fail, because the String constructor that takes an int parameter has been marked explicit. That means if I want to convert an int to a String, I have to do it explicitly:
f(String(2));
If the String(char const *); constructor were also marked explicit, then you wouldn't be able to call f("this is a string") either--you'd have to use f(String("this is a string"));
Note, however, that explicit only controls implicit conversion from some type foo to the type you defined. It has no effect on implicit conversion from some other type to the type your explicit constructor takes. So, your explicit constructor that takes type int will still take a floating point parameter:
f(String(1.2))
...because that involves an implicit conversion from double to int followed by an explicit conversion from int to String. If you want to prohibit a conversion from double to String, you'd do it by (for example) providing an overloaded constructor that takes a double, but then throws:
String(double) { throw("Conversion from double not allowed"); }
Now the implicit conversion from double to int won't happen--the double will be passed directly to your ctor without conversion.
As to what using explicit accomplishes: the primary point of using explicit is to prevent code from compiling that would otherwise compile. When combined with overloading, implicit conversions can lead to some rather strange selections at times.
It's easier to demonstrate a problem with conversion operators rather than constructors (because you can do it with only one class). For example, let's consider a tiny string class fairly similar to a lot that were written before people understood as much about how problematic implicit conversions can be:
class Foo {
std::string data;
public:
Foo(char const *s) : data(s) { }
Foo operator+(Foo const &other) { return (data + other.data).c_str(); }
operator char const *() { return data.c_str(); }
};
(I've cheated by using std::string to store the data, but the same would be true if I did like they did and stored a char *, and used new to allocate the memory).
Now, this makes things like this work fine:
Foo a("a");
Foo b("b");
std::cout << a + b;
...and, (of course) the result is that it prints out ab. But what happens if the user makes a minor mistake and types - where they intended to type +?
That's where things get ugly--the code still compiles and "works" (for some definition of the word), but prints out nonsense. In a quick test on my machine, I got -24, but don't count on duplicating that particular result.
The problem here stems from allowing implicit conversion from String to char *. When we try to subtract the two String objects, the compiler tries to figure out what we meant. Since it can't subtract them directly, it looks at whether it can convert them to some type that supports subtraction--and sure enough, char const * supports subtraction, so it converts both our String objects to char const *, then subtracts the two pointers.
If we mark that conversion as explicit instead:
explicit operator char const *() { return data.c_str(); }
...the code that tries to subtract two String objects simply won't compile.
The same basic idea can/does apply to explicit constructors, but the code to demonstrate it gets longer because we generally need at least a couple of different classes involved.
I've made this class BigInt, and it it has derived transformation constructors such as
BigInt::BigInt(int l):InfInt(l){}
Yet when I do something like this:
for(i=0;BigInt::pow(2,i+1)<exponent;i++);
The compiler yells at me for:
error: ambiguous overload for ‘operator+’ (operand types are ‘BigInt’ and ‘int’)
I know a simple way to fix this is simply to add (BigInt) in front of everything, like this:
for(i=0;BigInt::pow(2,i+(BigInt)1)<exponent;i++);
But this code looks ugly, somewhat hard to read, and is a pain to type. Is there a way to tell the compiler to do this right away (as the title already says) ? It's not too dramatic if there isn't though.
Oh, and excuse me if this has been already asked, but I have tried to search for a solution on my own on google and here and have found nothing that could help me out. (I was mostly able to find stuff about operator int() and the like, which I already knew about).
You also have an operator int(), don't you? That, plus the constructor that takes an int, produces the ambiguity. The compiler can call BigInt::operator+() by converting the int argument to a BigInt, or it can call the built-in + by converting the BigInt object to an int. Mark the operator int() explicit to get rid of this ambiguity. That will lead to failed conversions in a few situations, which can be resolved by adding a cast. That's the best you can do; there are no conversion precedence rules that can make the compiler see BigInt as the largest integral type.
Not sure what the problem is. Does comparing against this help:
#include <iostream>
struct MyInt
{
MyInt(int i) : m_i(i) {}
MyInt operator+(const MyInt& myint) const
{
return MyInt(m_i+myint.m_i);
}
int m_i;
};
int main()
{
MyInt a(10);
MyInt b(5);
MyInt c1 = a + b;
MyInt c2 = a + 5;
std::cout << c1.m_i << std::endl;
std::cout << c2.m_i << std::endl;
return 0;
}
EDIT: Following Mike Seymour's comment, I replaced operator std::string () const; with operator char * () const; and changed the implementation accordingly. This allows implicit casting, but, for some reason, the unsigned long int operator has precedence over the char * operator, which just does not feel right... Also, I don't want to expose nasty C stuff like char * outside the class, when I have std::string. I have a hunch that my CustomizedInt class needs to inherit from some stuff in order to support the feature that I desire. Could anybody please elaborate Mike's comment regarding std::basic_string? I'm not sure I understood it properly.
I have this piece of code:
#include <string>
#include <sstream>
#include <iostream>
class CustomizedInt
{
private:
int data;
public:
CustomizedInt() : data(123)
{
}
operator unsigned long int () const;
operator std::string () const;
};
CustomizedInt::operator unsigned long int () const
{
std::cout << "Called operator unsigned long int; ";
unsigned long int output;
output = (unsigned long int)data;
return output;
}
CustomizedInt::operator std::string () const
{
std::cout << "Called operator std::string; ";
std::stringstream ss;
ss << this->data;
return ss.str();
}
int main()
{
CustomizedInt x;
std::cout << x << std::endl;
return 0;
}
Which prints "Called operator unsigned long int; 123". My questions are these:
After I remove the operator unsigned long int, why do I need to cast x to std::string explicitly? Why does it not call the implicit cast operator (std::string) directly?
Is there any documentation that explains which implicit casts are allowed and which is their order of precedence? It seems that if I add an operator unsigned int to this class together with the operator unsigned long int, I receive a compiler error about ambiguity for the << operator...
Also, I know that defining such an operator may be poor practice, but I am not sure I fully understand the associated caveats. Could somebody please outline them? Would it be better practice to just define public methods ToUnsignedLongInt and ToString?
After I remove the operator unsigned long int, why do I need to cast x to std::string explicitly? Why does it not call the implicit cast operator (std::string) directly?
The version of << for strings is a template, parametrised by the parameters of the std::basic_string template (std::string itself being a specialisation of that template). It can only be chosen by argument-dependent lookup, and that only works if the argument is actually a specialisation of std::basic_string, not something convertible to that.
Is there any documentation that explains which implicit casts are allowed and which is their order of precedence?
The rules are quite complex, and you'd need to read the C++ standard for the full story. Simple rules of thumb are that implicit conversions can't contain more than one user-defined conversion and (as you've found out) the result of an implicit conversion can't be used to choose a template specialisation by argument-dependent lookup.
I am not sure I fully understand the associated caveats. Could somebody please outline them?
I don't fully understand them either; the interactions between implicit conversions, name lookup and template specialisation (and probably other factors that I can't think of right now) are rather complex, and most people don't have the inclination to learn them all. There are quite a few instances where implicit conversion won't happen, and others where it might happen when you don't expect it; personally, I find it easier just to avoid implicit conversions most of the time.
Would it be better practice to just define public methods ToUnsignedLongInt and ToString?
That's probably a good idea, to avoid unwanted conversions. You can fix your problem by leaving them and use them explicitly when necessary:
std::cout << std::string(x) << std::endl;
In C++11, you can declare them explicit, so that they can only be used in this manner. In my opinion, that would be the best option if you can; otherwise, I would use explicit conversion functions as you suggest.
By the way, the return type of main() must be int, not void.
With the following code, if I attempt to convert a template array to std::string, instead of the compiler using the expected std::string conversion method, it raises an ambiguity resolution problem (as it attempts to call the array conversion methods):
#include <iostream>
template<typename TemplateItem>
class TestA
{
public:
TemplateItem Array[10];
operator const TemplateItem *() const {return Array;}
operator const std::string() const;
};
template<>
TestA<char>::operator const std::string() const
{
std::string Temp("");
return Temp;
}
int main()
{
TestA<char> Test2;
std::string Temp("Empty");
Temp = Test2; //Ambiguity error. std::string or TemplateItem * ?
return 0;
}
What modification do I need to make to the code in order to make it so the code correctly and implicitly resolve to the std::string conversion function? Especially given the const TemplateItem * would be treated as a null-terminated array (which it won't likely be).
First, the reason you have ambiguity: you provide both conversion to char* and conversion to std::string const, and std::string likes them both.
By the way, before getting to your question, the const in operator std::string const was once a good idea, advocated by e.g. Scott Meyers, but is nowadays ungood: it prevents efficient moving.
Anyway, re the question, just avoid implicit conversions. Make those conversions explicit. Now I answered that in response to another SO question, and someone (I believe the person was trolling) commented that C++98 doesn't support explicit type conversion operators. Which was true enough, technically, but pretty stupid as a technical comment. Because you don't need to use the explicit keyword (supported by C++11), and indeed that's not a good way to make the conversions explicit. Instead just name those conversions: use named member functions, not conversion operators.
#include <iostream>
template<typename TemplateItem>
class TestA
{
public:
TemplateItem Array[10];
TemplateItem const* data() const { return Array; }
std::string str() const;
};
template<>
std::string TestA<char>::str() const
{
return "";
}
int main()
{
TestA<char> test2;
std::string temp( "Empty" );
temp = test2.str(); // OK.
temp = test2.data(); // Also OK.
}
Cheers & hth.
I will add, after thinking about it, here's the reasoning and what should be done:
The operator const TemplateItem *(); Should be deleted.
Why? There never will be an instance where you would want implicit conversion of TestA (or any template class) to a TemplateItem array with an unknown size - because this has absolutely no bounds checking (array could be sizeof 1 or 10 or 1000 or 0) and would likely cause a crash if a calling function or class received the array with no idea what size it is.
If the array is needed, either use the operator[] for direct items, or GetArray (which would signal the user intends to pass an unknown-length array).
Retain operator const std::string. Code will compile. Possible memory issues down the line averted.
(Alf for his efforts has been selected as the 'correct' answer, although this is the more logical option)
template <typename T>
class v3 {
private:
T _a[3];
public:
T & operator [] (unsigned int i) { return _a[i]; }
const T & operator [] (unsigned int i) const { return _a[i]; }
operator T * () { return _a; }
operator const T * () const { return _a; }
v3() {
_a[0] = 0; // works
_a[1] = 0;
_a[2] = 0;
}
v3(const v3<T> & v) {
_a[0] = v[0]; // Error 1 error C2666: 'v3<T>::operator []' : 2 overloads have similar conversions
_a[1] = v[1]; // Error 2 error C2666: 'v3<T>::operator []' : 2 overloads have similar conversions
_a[2] = v[2]; // Error 3 error C2666: 'v3<T>::operator []' : 2 overloads have similar conversions
}
};
int main(int argc, char ** argv)
{
v3<float> v1;
v3<float> v2(v1);
return 0;
}
If you read the rest of the error message (in the output window), it becomes a bit clearer:
1> could be 'const float &v3<T>::operator [](unsigned int) const'
1> with
1> [
1> T=float
1> ]
1> or 'built-in C++ operator[(const float *, int)'
1> while trying to match the argument list '(const v3<T>, int)'
1> with
1> [
1> T=float
1> ]
The compiler can't decide whether to use your overloaded operator[] or the built-in operator[] on the const T* that it can obtain by the following conversion function:
operator const T * () const { return _a; }
Both of the following are potentially valid interpretations of the offending lines:
v.operator float*()[0]
v.operator[](0)
You can remove the ambiguity by explicitly casting the integer indices to be unsigned so that no conversion is needed:
_a[0] = v[static_cast<unsigned int>(0)];
or by changing your overloaded operator[]s to take an int instead of an unsigned int, or by removing the operator T*() const (and probably the non-const version too, for completeness).
In simple terms: the compiler doesn't know whether to convert v to const float* and then use the operator[] for a pointer, or to convert 0 to unsigned int and then use the operator[] for const v3.
Fix is probably to remove the operator[]. I can't think of anything it gives you that the conversion operator to T* doesn't already. If you were planning to put some bounds-checking in operator[], then I'd say replace the conversion operators with getPointer functions (since in general you don't want to implicitly convert a safe thing to an unsafe thing), or do what std::vector does, which is that users get a pointer with &v[0].
Another change that lets it compile, is to change operator[] to take an int parameter instead of unsigned int. Then in your code, the compiler unambiguously chooses the interpretation with no conversion. According to my compiler, there is still no ambiguity even when using an unsigned index. Which is nice.
When you the compiler compiles the following
v[0]
it has to consider two possible interpretations
v.operator T*()[0] // built-in []
v.operator[](0) // overloaded []
Neither candidate is better than the other because each one requires a conversion. The first variant requires a user-defined conversion from v3<T> to T*. The second variant requires a standard conversion from int (0 is int) to unsigned int, since your overloaded [] requires an unsigned int argument. This makes these candidates uncomparable (neither is clearly better by C++ rules) and thus makes the call ambuguous.
If you invoke the operator as
v[0U]
the ambiguity will disappear (since 0U is already an unsigned int) and your overloaded [] will be selected. Alternatively, you can declare your overloaded [] with int argument. Or you can remove the conversion operator entirely. Or do something else to remove the ambiguity - you decide.
It is your type conversion operator that is the culprit. v transformed to a float pointer. Now there are two operator []s possible, one is the built in subscript operator for float and the other being the one you defined on v, which one should the language pick, so it is an ambiguity according to ISO.
Remember a class is a friend of itself:
v3(const v3<T> & v)
{
_a[0] = v._a[0];
_a[1] = v._a[1];
_a[2] = v._a[2];
}
When copy something of the same type you are already exposed to the implementation details. Thus it is not a problem to access the implementation directly if that is appropriate. So from the constructor you can access the object you are copying directly and see its member '_a'.
If you want to know the original problem:
The literal '1' in the context 'v[1]' is an integer (this is a synonym of signed integer). Thus to use the operator[] the compiler technically is required to insert a conversion from int to unisgned. The other alternative is to use the operator*() to get a pointer to the internal object and then use the [] operator on the pointer. Compiler is not allowed to make this choice and error out:
Compiler options:
_a[1] = v[1];
// Options 1:
_a[1] = v.operator[]((unsigned int)1);
// Options 2:
_a[1] = v.operator*()[1];
To make it unabigious you can use an unsigned literal;
_a[1] = v[1u];
In the long run it may be worth making this easier for the user.
Convert the operator[] to use int rather than unsigned int then you will get exact matches when integer literals (or you can have two sets of operator[]. One that uses int and one that uses unsigned int).
I didn't see it untill James McNellis posted the full error message, but the ambiguity is not between the two v3::operator[]() functions as it appears to be.
Instead, since there is no exact match between argument types, the compiler can't decide whether to:
a) Use v3::operator[](unsigned int) const, thereby converting the int argument to unsigned, or
b) Use the v3::operator const T*() const conversion followed by the built-in array indexing operator.
You can avoid this by making the operator[] arguments int's rather than unsigned ints. But a better solution would be to avoid an implicit conversion to T* and instead provide a Data() function that did that explicitly.
I had this same issue: I resolved it simply making the typecast operator explicit.
The const version doesn't modify anything. The non-const version allows you to assign things using array notation (v[3] = 0.5;).