I'm looking to use some c++11 features in some existing c++ projects, so I started changing compile flags in Clang for some projects, and I keep running into a specific issue regarding C++11's treatment of conversion operators (or cast operators) that I didn't expect to see and don't understand why this is now considered an error when it's been valid C++ code that's not c++11
I've boiled it down to this simple example:
#include <iostream>
#include <vector>
class SerializableFormat
{
public:
size_t i;
};
class A
{
public:
size_t x, y;
A(size_t n) : x(n), y(1) { }
operator const SerializableFormat() const
{
SerializableFormat result;
result.i = x;
if (y)
{
result.i /= y;
}
return result;
}
};
int main(int argc, const char * argv[])
{
std::vector<SerializableFormat> v;
for(size_t i = 0; i < 20; i++)
{
v.push_back(A(i));
}
return 0;
}
If Clang's compilation flags are set to -std=c++98 and libstdc++, there are no issues and this compiles fine.
If Clang's compilation flags are set to -std=c++11 and libc++, I get the error No viable conversion from 'A' to 'value_type' (aka 'SerializableFormat')
Just to make it clear-- in case you're thinking about giving SerializableFormat a constructor just for the class A:
Since the SerializableFormat class is more suited for conversion to and from various classes, it makes sense for A (and other classes that wish to be serializable) to have constructors and conversion operators rather than expect SerializableFormat to cover every type of class that wants to be serializable, so modifying SerializableFormat to have a special constructor is not a solution.
Can anyone see what I'm doing wrong here?
As the comments correctly note, you can get compiling by dropping the const in the return type of your SerializableFormat conversion operator:
operator const SerializableFormat() const
As to whether clang is correct in this behavior is a matter of some dispute. The issue is being tracked by clang bug report 16682. At this time there is talk of creating a CWG (C++ committee) issue report, but that has not yet been done. I note that this bug report has been open for some time now (2013-07-23), but was updated as recently as 2015-01-28.
In the meantime, practical advice is just never to return by const-value. This was decent advice for C++98/03, but with move semantics becomes bad advice because it will disable move semantics.
Related
How does typecast overloading work exactly?
In the following example there are two typecast overloading in class test.
In visual studio 2008 it always calls the int version, but in absence of int it calls char version. How does it decide which one to call?
And is it even recommended to have such ambiguous overloading in same class?
class test
{
public:
int a;
test():a(2){}
operator char()
{
return 'c';
}
operator int()
{
return 2;
}
};
int main()
{
test obj;
cout<<obj;
return 0;
}
Well, usually if you provide multiple implicit conversion operator, then you should be explicit about the conversion if the target function have multiple overloads. In some cases, you might want to make some conversions explicit.
In most cases, I would say that the best solution would be do use a temporary variable in such cases. For example:
char c = test; // or even better char c { test };
cout << c;
The main advantage of this over casts is that you ensure that the desired conversion is available.
I have done a few tests with conversion operators and I think that VC would sometime use a conversion operator that should not be allowed. For example,
char c { test };
would compile with VC even if I remove the conversion to char operator. I think it should give a narrowing conversion error instead. It does works in trivial cases like
int x = 345;
char c { x }; // An error as expected
You could also use static_cast for your conversion if you prefer.
Why can one cast a std::ostream to a void pointer? I am not aware of any such conversion operator in std::ostream. Code below
#include <iostream>
int main()
{
void *p = std::cout; // why does this work?
}
I'm asking this question since I've seen a placement operator new invoked as
Foo* pFoo = new (std::cerr) Foo;
and have absolutely no idea why would one write such a thing.
PS: I am compiling with g++ 4.9.2 with or without -std=c++11. clang++ does not accept the code.
PSS: Found out that due to the so called "safe bool problem" (see #nicebyte's answer), in pre C++11 a void* conversion operator was defined for std::ostream, which was then removed in C++11. However, my code compiles fine in C++11 using g++. More than that, clang++ rejects it no matter what version of the standard I use, even with -std=c++98, although my understanding is that it should accept if compiled as pre-C++11.
Read this (your question is answered in the very last section, "The safe bool problem").
To elaborate a bit, the implementation defines an implicit conversion to void* defined for things like std::cin and std::cout, just so that code like while(std::cin>>x){...} compiles, while code like int x = std::cin; doesn't. It's still problematic because you can write stuff like in your example.
C++11 solves this problem by introducing explicit conversions.
An explicit conversion operator looks like this:
struct A {
explicit operator B() { ... } // explicit conversion to B
};
When A has an explicit conversion to B, code like this becomes legal:
A a;
B b(a);
However, code like this is not:
A a;
B b = a;
A construct like if(std::cin) requires cin to be converted to bool, the standard states that in order for the conversion to be valid in that particular case, code like bool x(std::cin); should be "legal". Which can be achieved by adding an explicit conversion to bool. It allows cin/cout to be used in the above context, while avoiding things like int x = std::cout;.
For more information, refer to Bjarne's page as well as this question.
Answering only the follow-up, since nicebyte's answer is perfect for the original question.
Chances are, your gcc is set up to use libstdc++ (which hasn't changed the operator yet due it being an ABI-breaking change), and your clang is set up to use libc++ (which was from the beginning intended as a C++11 standard library and isn't quite conformant in C++98 mode - it provides a bool conversion operator that is explicit in C++11).
I think it's to allow for if (std::cout) ... without allowing for implicit conversion to bool, or something like that.
I've got the following code (reduced from the actual application, of
course):
class Reader
{
class Proxy
{
Reader* myOwner;
public:
Proxy( Reader* owner ) : myOwner( owner ) {}
template <typename T>
operator T() const
{
T tmp;
myOwner->Read( &tmp );
return tmp;
}
};
public:
void Read( bool* dest );
void Read( int* dest );
void Read( std::string* dest );
// ...
Proxy Read();
};
void
testIt( Reader& r )
{
std::string s = r.Read(); // Issue on this line.
}
The code compiles fine with both MSC and g++, but Intellisense
highlights the line in question, with an error message to the effect
that more than one user defined conversion from Reader::Proxy to
std::string applies, and cites all or most of the constructors of
std::string which can be called with a single argument.
My real question is: who is right? My feeling is that because I'm using
the copy initialization form of initialization, the compiler should
first convert Reader::Proxy to an std::string, then copy this.
And that the instantiation Proxy::operator std::string() does the conversion
with a single user defined conversion, where as an instantiation like
Proxy::operator char const*() would require two: the conversion
operator and the conversion constructor of std::string, and would thus
be illegal. (If I'd used direct initialization, of course, the compiler
would search for all of the conversions which could be used to call
a constructor of std::string, and the statement would be ambiguous.)
So is this a bug in Intellisense? Or is it a case of Intellisense being
closer to the standard, and that my code might stop compiling when we
upgrade, and the newer version follows the standard more closely?
Generally if it works in MSVC and g++ but not Intellisense, it's probably Intellisense that's at fault.
That said, I believe the code you posted is fine.
There is actually an MSVC warning for this (C4928), though it's off by default:
http://msdn.microsoft.com/en-us/library/cwck4ta9.aspx
You can enable it by using /w44928 on the command line or in 'extra compile options' in the IDE, or by using #pragma warning(4:4928).
EDIT: Having read the MSDN docs on that warning, it looks like they're suggesting that changing your code to std::string s(r.Read()); will work without warning. So I guess their wording of the warning isn't quite right (or we're just misreading it?) and they really mean "user-defined conversion and copy initialization being done in one statement". I don't know if that's allowed by the standard or not, sorry.
I'm working on a legacy library that needs to be backwards compatible with C++03, but is also forward compatible to take advantage of C++11 features like move semantics and explicit casting.
So, is it possible to emulate explicit casting in C++03? I know obviously about the explicit bool (or "safe" bool) idiom - but that's only for casting to a boolean type. Is it possible to emulate a general explicit cast operator in C++03?
I checked around, and found a discussion about this in a book called "Imperfect C++ : Practical Solutions for Real-Life Programming".
In this book, they discuss some ideas about emulating an explicit cast in C++03 (the book was written before C++11). Ultimately, they recommend creating an explicit_cast<T> template. However, I don't like that solution because I want users to simply be able to use static_cast<T>, which works fine in C++11.
So, another solution was to force the compiler to do two conversions, which will disallow implicit conversions. An example of that would be something like:
class int_cast
{
public:
int_cast(const int& v) : m_value(v)
{ }
operator int() const
{
return m_value;
}
private:
int m_value;
};
struct Foo
{
Foo()
{
x = 10;
}
operator int_cast() const
{
return int_cast(x);
}
int x;
};
Here, a Foo should be explicitly convertible to int, but not implicitly. (This code is lifted almost verbatim from Imperfect C++, except in their example they are converting a custom Time object to a std::tm.
However, this doesn't actually work, at least not using GCC 4.7.2:
Foo f;
int x = static_cast<int>(f);
This results in :
test3.cpp: In function ‘int main()’:
test3.cpp:44:28: error: invalid static_cast from type ‘Foo’ to type ‘int’
So I guess "Imperfect C++" is wrong here. The compiler wasn't able to convert a Foo to an int, even with an explicit cast. (Maybe this worked on older compilers?) So, is there anyway to emulate this in C++03 (without using a custom cast operator)?
"Imperfect C++" is right, because it uses a custom "keyword" - actually a function name masquerading as a keyword (not unlike eg.: Tribool's indeterminate). If you try to static_cast you crash against the limitation that the language can only accept conversion chains that involve up to one user-defined type, whereas you have two conversions - from "Foo" to "int_cast" and from there to int.
If you want specifically to be able to static_cast then you'll probably have to hack something with macros to supersede normal static_cast... and accept to live in Undefined Behaviour Land. My preferred choice is to actually work in the inverse direction: simply use explicit_cast and use a macro to redefine it as a static_cast invocation when in C++11 mode. I use explicit cast in my C++ backports toolkit and thus in all the C++ code I write, and I have found no important issues so far.
I have the following piece of code:
typedef int AliasB;
typedef unsigned short AliasA;
class Alias
{
public:
explicit Alias(int someInt) { }
};
// (*) !! below breaks the conversion path via AliasA !!
//typedef Alias AliasA;
class C
{
public:
C() { }
};
class B
{
public:
B() { }
B(const AliasB& value) { }
operator AliasB() const
{
return -1000;
}
C combine(const B& someB)
{
return C();
}
};
class A
{
public:
A() { }
operator B() const
{
return B();
}
operator AliasA() const
{
return 1001;
// (*) !! below breaks the conversion path via AliasA !!
//return AliasA(1000);
}
A high()
{
return A();
}
A low()
{
return A();
}
C process()
{
return (static_cast<B>(low())).combine(static_cast<B>(high()));
// (**) !! the below compiles fine !!
//B theB = low();
//return theB.combine(high());
}
};
inline int someFunc(unsigned int someParam, const B& bParam)
{
return 1;
}
inline A createSomeA()
{
return A();
}
int main ()
{
A someA;
unsigned int counter = 200;
someFunc(counter, someA);
//someFunc(counter, static_cast<B>(createSomeA()));
someA.process();
return 0;
}
Clang reports the following error:
clang_static_test.cpp:66:17: error: ambiguous conversion for static_cast from 'A' to 'B'
return (static_cast<B>(low())).combine(static_cast<B>(high()));
^~~~~~~~~~~~~~~~~~~~~
clang_static_test.cpp:21:7: note: candidate is the implicit copy constructor
class B
^
clang_static_test.cpp:25:5: note: candidate constructor
B(const AliasB& value) { }
^
clang_static_test.cpp:66:48: error: ambiguous conversion for static_cast from 'A' to 'B'
return (static_cast<B>(low())).combine(static_cast<B>(high()));
^~~~~~~~~~~~~~~~~~~~~~
clang_static_test.cpp:21:7: note: candidate is the implicit copy constructor
class B
^
clang_static_test.cpp:25:5: note: candidate constructor
B(const AliasB& value) { }
^
2 errors generated.
I can't figure out why is the compiler generating an error although I have the
conversion operator defined and I make the conversion at that specific place explicit using static_cast<>.
The code passes compilation with GCC 4.5.2 and Visual Studio 2008 compilers.
Clang version is 3.1, built by myself from the git repositories of Clang and LLVM
a couple of days ago.
So, is Clang reporting an actual error? And if yes, why is it an error as it's
not obvious to me at all(I won't ask why the other compilers are silent about that)?
UPDATE: the sample code is now a small compilable example(sorry for not doing this from the first time) and replicating the real situation I have. It seems that the conversion operator to AliasA is the problem, because if it's removed then everything compiles fine. The nasty thing right now is that for the above piece of code I get errors also from GCC.
UPDATE 2: I added some code to the sample to reflect better my real situation; the only difference is that for the above sample I also get an error from GCC, whereas for my real code I don't.
There are two ways for static_cast to convert an A into a B:
use A::operator B and call the implicit copy constructor B::B(const B& value) to create the new B
use A::operator AliasA, convert the result to AliasB and call B::B(const AliasB& value)
The compiler does not know which way to prefer. You can give a hint to use the second option by writing:
someFunc(counter, static_cast<AliasA>(someA));
To use the first option you can omit the cast by simply writing:
someFunc(counter, someA);
Well, I'm not sure if the latter is well definined behaviour, but it works at least with gcc and msvc.
I have filed a bug report about this to clang. They argue that it is not a bug. The C++ standard lacks a specification for this case and therefore the compiler reports it as ambiguous. See bug report.
I think this behavior is counter-intuitive. The first path through A::operator B() is a perfect match, while the second path involves three type conversions. The only logical thing to do is to regard the perfect match as superior.
What should a compiler do when a case is not explicitly resolved in the C++ standard?
Produce an error message
Make a logical choice by analogy to other rules
Contact the C++ standards committee and tell them to revise the standard.
?
I think I figured out in part what is happening, but I don't think I comprehend the whole situation. So the conversions paths the compiler sees look like below:
/-------- A --------\
| |
| |
B AliasA(unsigned short)
| |
| |
copy ctor of B AliasB(int)
|
|
ctor B(const AliasB& value)
So it makes sense and the compiler is right in reporting the ambiguity(I love clan'g error and warning messages). One way to make it work is to break the conversion path via the AliasA(see the comments marked with (*) in the sample code in the question). It also works if I break the offending expression and rely only on implicit conversion, not trying to explicitly static_cast<> anything( see the comments marked with (**) in the sample code in the question). But I don't grasp completely what's happening behind the scenes. I still don't understand completely why it behaves different in the (**) case because the conversion paths seem to be the same, at least for the "theB.combine(high())" part.