Compile error 'nullptr' undeclared identifier - c++

I'm trying to compile a source with Visual Studio 2008 Express, but I'm getting this error:
Error C2065: 'nullptr' undeclared identifier.
My code:
if (Data == nullptr) {
show("Data is null");
return 0;
}
I read on Google that I should upgrade to Visual Studio 2010, but I don't want to do this because of the IntelliSense in Visual Studio 2008. Can this be repaired or replaced?

The error you are getting is because the compiler doesn't recognize the nullptr keyword. This is because nullptr was introduced in a later version of visual studio than the one you are using.
There's 2 ways you might go about getting this to work in an older version. One idea comes from Scott Meyers c++ book where he suggests creating a header with a class that emulates nullptr like this:
const // It is a const object...
class nullptr_t
{
public:
template<class T>
inline operator T*() const // convertible to any type of null non-member pointer...
{ return 0; }
template<class C, class T>
inline operator T C::*() const // or any type of null member pointer...
{ return 0; }
private:
void operator&() const; // Can't take address of nullptr
} nullptr = {};
This way you just need to conditionally include the file based on the version of msvc
#if _MSC_VER < 1600 //MSVC version <8
#include "nullptr_emulation.h"
#endif
This has the advantage of using the same keyword and makes upgrading to a new compiler a fair bit easier (and please do upgrade if you can). If you now compile with a newer compiler then your custom code doesn't get used at all and you are only using the c++ language, I feel as though this is important going forward.
If you don't want to take that approach you could go with something that emulates the old C style approach (#define NULL ((void *)0)) where you make a macro for NULL like this:
#define NULL 0
if(data == NULL){
}
Note that this isn't quite the same as NULL as found in C, for more discussion on that see this question: Why are NULL pointers defined differently in C and C++?
The downsides to this is that you have to change the source code and it is not typesafe like nullptr. So use this with caution, it can introduce some subtle bugs if you aren't careful and it was these subtle bugs that motivated the development of nullptr in the first place.

nullptr is part of C++11, in C++03 you simply use 0:
if (!Data)

When it's not recommended to edit sources, you can just give your c++ compiler appropriate define. For example, in CMakeLists.txt I've added line:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Dnullptr=0")
And everything worked well

Related

Fixing odd compiler errors with std:: qualifier

I'm attempting to build source files of an open source C++ library written by someone else. This is being done on Windows with Cygwin's mingw-w64 compiler. The only compiler option I'm attaching is -std=gnu++11 since the library depends on some C++11 features.
Here are some examples of code in their library that appears to be causing issues:
CPScalar & Abs()
{
m_dValue = std::abs(m_dValue);
return *this;
}
//...
template<typename Unit>
bool SEScalarQuantity<Unit>::Set(const SEScalarQuantity<Unit>& s)
{
if (m_readOnly)
throw CommonDataModelException("Scalar is marked read-only");
if (!s.IsValid())
return false;
m_value = s.m_value;
m_isnan = (std::isnan(m_value)) ? true : false;
m_isinf = (std::isinf(m_value)) ? true : false;
m_unit = s.m_unit;
return true;
}
I get compiler errors on the std:: qualified functions above. The compiler error on the m_dValue = std::abs(m_dValue); line is
error: call of overloaded 'abs(double&)' is ambiguous
Which made me think it could be related to the question of whether std::abs(0u) is ill-formed as well as this answer to a similar SO question.
m_isnan = (std::isnan(m_value)) ? true : false; and the following line gives me
error: expected unqualified-id before '(' token
There are countless other uses of std:: that the compiler doesn't complain about. If I remove all of the std:: qualifiers in the statements that are giving me errors, the code compiles beautifully.
Thing is, this open source project is (presumably) being built by others without modification, so what am I missing here?
Add #include <cmath> to the file being compiled. The problem is that there are a couple of overloads of std::abs for integer types that are declared in the header <cstdlib> and the compiler is complaining that it doesn't know which of those to use. What's needed, though, is std::abs(double), and that's declared in <cmath>.
The reason that this code works with some compilers and not others is probably that there is a declaration of std::abs(double) coming in from some header other than <cmath>. That's allowed, but not required.

Lambdas in variadic templates

Using Microsoft Visual C++ 2013 (12.0), I am encountering compile-time errors when using a lambda in a constructor in a variadic template. I have managed to boil it down as shown below (see the lines with the error comments). It appears to be a bug in 12.0 that is not present in 14.0. I haven't tried other versions. Is there any documentation on this bug, perhaps in the form of a release note that clarifies the conditions under which this bug occurs and which states that it has been explicitly fixed?
#include <functional>
// a simple method that can take a lambda
void MyFunction(const std::function<void()>& f) {}
// a simple class that can take a lambda
class MyClass
{
public:
MyClass(const std::function<void()>& f) {}
};
// non-templated test
void test1()
{
MyFunction([] {}); // OK
MyClass([] {}); // OK
MyClass o([] {}); // OK
}
// non-variadic template test
template<typename T>
void test2()
{
MyFunction([] {}); // OK
MyClass([] {}); // OK
MyClass o([] {}); // OK
}
// variadic template test
template<typename... T>
void test3()
{
MyFunction([] {}); // OK
MyClass([] {}); // OK
MyClass a([] {}); // error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
// error C2440: 'initializing' : cannot convert from 'test3::<lambda_12595f14a5437138aca1906ad0f32cb0>' to 'int'
MyClass b(([] {})); // putting the lambda in an extra () seems to fix the problem
}
// a function using the templates above must be present
int main()
{
test1();
test2<int>();
test3<int, int, int>();
return 1;
}
Edit/Update: MSVC 2013 compiler seem to have this bug, latest versions fixed that. GCC and clang compilers don't show any error.
I can't say is that bug or not, back days Microsoft was not so eager to latest C++ standards, it was two steps behind GCC and CLang, and it's not a surprise to know that no-one implement a whole standard in one compiler update. Some stuff from std library may be partially implemented, for example Visual Studio usually implements new features under std::experimental namespace (filesystem for VS2013), but something like compiler lexemes can't be added that way.
For common information about standard compatibility I suggest to use compiler support article https://en.cppreference.com/w/cpp/compiler_support/11 (MSVC means _MSC_VER definition) and
https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance more for detailed information about Visual Studio. Here https://en.wikipedia.org/wiki/Microsoft_Visual_C++#Internal_version_numbering you can find _MSC_VER version along with related Visual Studio version, source is https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros.
Based on those articles I believe that your problem lays in between "Variadic templates" and "Lambda expression" both are fully supported from Visual Studio 19.0, searching _MSC_VER 1900 in wiki that means Visual Studio 2015 (Update 2, if to be precise according to Microsoft article).
vs2015 can be compiled normally, because vs2015 can fully support the c++11 standard, you can consider upgrading your vs

error C2027: the gcc vs msvc case

This simple snippet of code
class S;
class G
{
void onRead(S & s)
{
(void)s;
}
};
perfectly works on GCC. Using that (void)s is a very useful way to avoid the warning "unused variable 's'". But MSVC sees this as an error, stopping the compilation.
It gives the infamous error C2027: use of undefined type 's'. But here 's' its not used at all.
How can I solve this kind of trouble?
I don't want to use the form of void onRead(S &) because you can't see it in this little snippet example, but in my code that 's' name is really meaningful, and useful to understand the parameters.
There are a couple of alternate ways of avoiding the error.
The most straight-forward is to convert the variable name to a comment:
void onRead(S & /* s */)
Another is to use a macro to remove the variable:
#define UNUSED(x)
void onRead(S & UNUSED(s))
I'm sure you've already thought of just moving the code to a point where S is fully defined and there's some reason you can't do that.
You can't use "s" because the class "S" hasn't been fully defined. You can:
1) Disable the warning with #pragma warning(disable:4100)
2) Move the body of the onRead function to a place where "S" has been fully defined
3) Move the definition of "S" so it is before onRead
4) Use a void pointer: (void*)&s;

Compiler Robustness ... Naivete

I use Visual Studio Professional 2012. I pre-compiled a class (header and source) successfully. Days later, when compiling another class (for the moment header only) that is utilizing the previous one, the compiler caught a missing reference if(this != &rhs) and semicolon rhs.root = nullptr;.
Perhaps it is my naivete and lack of knowledge about how compilers work but I thought a compiler was robust to catch errors such as these. It appeared to me that only when a specific block of code was required did the compiler feel the need to check it.
I have read about just-in-time compilation and learned how assembly compilers perform a two-pass compilation with symbols first and then syntax. I have not taken a course in compiler construction at my university and I know such courses give great insight into parsers, etc.
The code section where it failed to catch the error is this move assignment operator:
Tree &operator=(Tree &&rhs)
{
if(this != rhs) <--------- no reference to the rhs
{
root = std::move(rhs.root);
rhs.root = nullptr <----------- no semicoln
}
return *this;
}
The errors were generated while compiling boost variant, as well as my visitor class member:
bool operator() (Tree<std::string>& tree) const {
return tree.load(tree);
}
as well as a host of other errors related to boost serialization. The fix was to, of course, correct the missing reference and semicolon but I want to understand why this was caught apparently only when the compiler needed to touch this code?
Is it a template class?
Because semantic analysis of templates makes only sense when they are instantiated. That is, if it is a template, the compiler should generate an error at the missing semicolon (syntactic error), but not at the == operator.
The following code compiles with g++:
template<typename T>
struct A {
void q(A &a) {
if (this == a) {}
}
};
int main(int argc, char **argv) {
A<int> x;
//x.q(x);
}
But doesn't compile when
x.q(x);
is uncommented.

Passing multi-param function into a macro

Why does this not compile on VC 2005?
bool isTrue(bool, bool) { return true; }
void foo();
#define DO_IF(condition, ...) if (condition) foo(__VA_ARGS__);
void run()
{
DO_IF(isTrue(true, true)); // error C2143: syntax error : missing ')' before 'constant'
}
Running this through the preprocessor alone outputs:
bool isTrue(bool, bool) { return true; }
void foo();
void run()
{
if (isTrue(true true)) foo();;
}
Notice the missing comma in the penultimate line.
Last Edit:
LOL!
bool isTrue(bool, bool) { return true; }
void foo();
#define DO_IF(condition, ...) if (condition) { foo(__VA_ARGS__); }
void run()
{
DO_IF(isTrue(true ,, true)); // ROTFL - This Compiles :)
}
Macros with indefinite numbers of arguments don't exist in the 1990 C standard or the current C++ standard. I think they were introduced in the 1999 C standard, and implementations were rather slow to adopt the changes from that standard. They will be in the forthcoming C++ standard (which I think is likely to come out next year).
I haven't bothered to track C99 compliance in Visual Studio, mostly because the only things I use C for anymore require extreme portability, and I can't get that with C99 yet. However, it's quite likely that VS 2005 lacked parts of C99 that VS2008 had.
Alternately, it could be that you were compiling the program as C++. Check your compiler properties.
Run your code through CPP (C preprocessor) to see what substitutions CPP does for your macro.
You could do it either by invoking cpp or providing -E parameter to compiler (if you use gcc, of course).
Various preprocessor implementations parse the commas greedily, treating them as separators for macro arguments. Thus, CPP thinks that you're asking "DO_IF" to do a substitution with two parameters, "isTrue(true" and "true)".
Your code compiles just fine in VS2008, if i change DO_IF to RETURN_IF. However, this should not change anything relevant for your error.
Edit: Still compiles without errors, even after your changes.
I think that should work, except, shouldn't it be...
RETURN_IF(isTrue(b, !b));
and
RETURN_IF(isTrue(b, b));