I saw that nullptr was implemented in Visual Studio 2010. I like the concept and want to start using it as soon as possible; however GCC does not support it yet. My code needs to run on both (but doesn't have to compile with other compilers).
Is there a way to "emulate" it? Something like:
#define nullptr NULL
(That obviously wouldn't work well at all, it's just to show what I mean.)
The Official proposal has a workaround -
const // this is a const object...
class {
public:
template<class T> // convertible to any type
operator T*() const // of null non-member
{ return 0; } // pointer...
template<class C, class T> // or any type of null
operator T C::*() const // member pointer...
{ return 0; }
private:
void operator&() const; // whose address can't be taken
} nullptr = {}; // and whose name is nullptr
It looks like gcc supports nullptr as of 4.6.
Also, gcc (actually g++) has had an extension __null for years. This was counted as industry implementation experience when the nullptr proposal came out.
The __null extension can detect special cases and warn about them such as accidentally passing NULL to a bool parameter, when it was intended to be passed to a pointer parameter (changes made to a function, forgot to adapt the call side).
Of course this isn't portable. The template solution above is portable.
It looks by gcc 4.6.1 (Ubuntu 11.11 oneiric), nullptr has been added.
A quick, recursive sed find-and-replace on my hpp/cpp files worked fine for me:
find . -name "*.[hc]pp" | xargs sed -i 's/NULL/nullptr/g'
It's most likely you forgot -std=c++0x .
My Mingw version of gcc is 4.6.1/4.7.1, both support nullptr well.
According to description in "The c++ standard library, a tutorial and reference, 2nd", nullptr is a keyword, can automatically convert to each pointer type but not integer type, this overcome the drawback of NULL, which is ambiguous to the following overload function:
void f(int );
void f(void *);
f(NULL); // Ambiguous
f(nullptr); // OK
Test this feature in VC2010 shows that the MSDN document conflicts with the actual compiler, the document said:
The nullptr keyword is not a type and is not supported for use with:
sizeof
typeid
throw nullptr
Actually in VC2010, all of the above operator/expression is legal. sizeof(nullptr) result 4. typeid.name() result std::nullptr_t, and throw nullptr can be caught by "const void *" and "void *"(and other pointer types).
While gcc(4.7.1) looks more rigid about nullptr, throw nullptr cannot be caught by "void *", can be caught by '...'
Related
I'm trying to use QSet for storing a list of function pointers. See this code for more details. The problem is that this code does not compile by gcc/mingw. MSVC compiles it normally. What am I doing wrong?
typedef intptr_t (*UikHook)(intptr_t);
...
typedef struct
{
QSet<UikHook>* qsetSubscribers;
//QMutex* qmutexHook;
} THookableEvent;
...
THookableEvent* p = qmapHooks_.value(name);
if (p->qsetSubscribers == 0)
p->qsetSubscribers = new QSet<UikHook>();
p->qsetSubscribers->insert(hookProc);
error: no matching function for call to ‘qHash(long int (* const&)(long int))’
Perhaps, I should to declare operator== and function qHash() for type UikHook as it said in the docs, but I dont know how to do it because when I'm declaring opertator==, I get the following error:
inline bool operator==(const UikHook &e1, const UikHook &e2)
error: ‘bool operator==(intptr_t (* const&)(intptr_t), intptr_t (* const&)(intptr_t))’
must have an argument of class or enumerated type
P.S. I'm using Qt 5.8, gcc 6.2, msvc2015
Update: Solved by replacing QSet to QVector.
You can't define an operator== for built-in types, such as pointers, integers or floating-point numbers. They already have it. You just need to provide a qHash.
Using function pointers is not really the best practice in C++. In early C++ versions, functors were used instead. Since C++11, there are real function objects. You can convert a function pointer to an object via std::function() (Reference).
If the compilers you listed are the ones you need to support, I strongly suggest using std::function instead of function pointers.
Try (warning, brain compile):
template <typename R, typename ...A>
inline uint qHash(R (*)(A...) const f) noexcept
{
return std::hash<R (*)(A...)>()(f);
}
Qt is in a fix here, since it can't use the STL and hashing function pointers is somewhat compiler specific.
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 have a function
void foo(int *bar)
{}
Visual Studio 2012 will now happily and without warnings compile if I call foo like this:
int main()
{
foo(false);
return 0;
}
If I however change foo(false) to foo(true) than I get an error:
1>main.cpp(132): error C2664: 'foo' : cannot convert parameter 1 from 'bool' to 'int *'
1> Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
Any idea how I can make sure that I get an error when passing false, too? My only idea is to add a second private function "void foo(bool bar)". Then I indeed get the desired error stating that foo(bool bar) is private. But this only works when foo is called from outside the class and it clutters my interface.
First, as to why it accepts false but not true: The literal false will be interpreted as the integral 0 and a literal 0 will convert to a null pointer of any type. true on the other hand cannot be converted to a pointer type as it converts to an integral 1.
As to how to solve your problem: Your approach with an extra bool overload will work fine for both public and non-public callers as long as you don't implement the private overload. In that case public callers will get a compile error and member callers will get a linker error.
However, you may wish to consider additional things as well.
Does your function need to accept null pointers? If not, change it to accept by reference instead and the problem just goes away.
If your function really does need to accept null pointers then I would suggest in this case to just trust your users to call it correctly instead of cluttering your interface trying to prevent every possible misuse.
In C++11, you may write:
void foo(bool) = delete; // cannot be use by anybody (class itself included).
As vs2012 doesn't support = delete,
You may try this hack using SFINAE:
template <typename T>
typename std::enable_if<std::is_same<T, int>::value, void>::type
foo(T* t);
With the old C++98 way 'private without implementation':
private: // Fail to compile from outside
void foo(bool); // No implementation -> fail to link time if internally used.
You can wait for C++17, when Concepts can be used anywhere auto is in C++11, and write your signature as:
void foo( IsActually<int*>::template test x ) { }
... which actually looks pretty bad, but they may clean up the syntax by then.
Just a question something I found interesting when working with stl. In the below code, the last two lines in the main function will cause the error (indicated in the comments). However, the test_func compiles fine. Since type being passed to the template function is a reference type and the function itself applies the & operator aren't these two things essentially the same? well, apparently not cause one of them compiles and the other doesn't. Anyone know why?
class File {
private:
std::string name_;
public:
File(std::string n) : name_(n) {}
std::string name() const { return name_; }
};
std::ostream& operator<<(std::ostream& os, const File& f)
{
os << f.name();
return os;
}
template <class T> void test_func(const T& v)
{
T& v1(v);
std::cout << "File:" << v1 << std::endl;
}
typedef File& FileRef;
int main(int argc, char* argv[])
{
File f("test_file");
test_func<File&>(f);
// FileRef& fRef1(f); ==> error; cannot declare reference to 'class File&'
// File&& fRef2(f); ==> error; expected unqualified-id before '&&' token
}
UPDATE: I came across this when working with bind1st and bind2nd functions in ; they are defined just like test_func in the text book (stroustrup in Chapter 18 section on binders) so it can't be wrong.
The first commented line is legal, and your compiler is probably not conforming with C++11. Because of C++11's reference collapsing rules, in fact, it should declare an lvalue reference to File named fRef1 and bind it to the lvalue f.
The second commented line is illegal: you cannot bind an rvalue reference to an lvalue. However, the error you are getting seems to indicate that the compiler does not understand the && token.
If you are using Clang or GCC, make sure you are compiling with the -std=c++11 or -std=c++0x option.
UPDATE:
In C++03, both lines are illegal, and even this function call should be rejected by the compiler:
test_func<File&>(f); // SHOULD BE AN ERROR! (substitution failure)
Per paragraph 14.8.2/2 of the C++03 Standard:
[...] Type deduction may fail for
the following reasons:
— [...]
— Attempting to create a reference to a reference type or a reference to void.
— [...]
This can mean two things: either your compiler has a bug, or it intentionally decides to ignore an attempt to create a reference to reference in the context of template argument deduction (and only in that context) - meaning that you're dealing with a compiler extension.
In any case, that function call is ill-formed and therefore not portable.
I think the function works, because the compiler is clever enough not to make a reference of a reference. He gets a reference and wants a reference, so it stays one. I think he simply ignores the second & when you have T& with T already a reference.
I can't explain it in detail but in c++ you can use references mostly exactly like non-references.
In FileRef& he can't ignore that. Here you explicitly say: make a reference of a reference, what can't work.
And && is a logical AND.
ps: substitution failure is not an error (SFINAE)