Firstly, std::nullptr_t is a core language type, so why is it in the std namespace? You don't see std::char or std::int.
Secondly, where is it in the std namespace? When I right click in Visual Studio to see where it is declared, it says "the symbol nullptr_t is not located in any source file." If std::nullptr_t is not declared in the std namespace, why does code containing std::nullptr_t compile?
EDIT:
This link on microsoft's website says nullptr is a built in type, and that built in types are not defined in header files.
std::nullptr_t is a core language type
std::nullptr_t is a fundamental type(aka built in type) as explained here. It is not even a pointer type though it can be implicitly converted to any pointer type. Moreover, it is defined inside header cstddef in namepsace std as quoted below.
This can be seen from lex.nullptr:
The pointer literal is the keyword nullptr. It is a prvalue of type std::nullptr_t.
[ Note: std::nullptr_t is a distinct type that is neither a pointer type nor a pointer-to-member type; rather, a prvalue of this type is a null pointer constant and can be converted to a null pointer value or null member pointer value.
See [conv.ptr] and [conv.mem].
— end note
]
From cstddef.syn:
Header <cstddef> synopsis
namespace std {
using nullptr_t = decltype(nullptr);
//other things here
}
In both libstdc++, libc++, and MSVC's STL, std::nullptr_t is a typedef for decltype(nullptr).
So yes, the type is a core language type, but it doesn't have a name, and the only way to refer to it (without the header) is with decltype(nullptr).
As others have stated, std::nullptr_t is a special type. It is to be distinguished from nullptr itself - which is a value.
There are some use cases for std::nullptr_t.
For example function overloads:
void foo(int*);
void foo(nullptr_t);
int main() {
int a = 4;
int* b = &a;
foo(b); // will call foo(int*)
foo(nullptr); // will call foo(nullptr_t)
b = nullptr;
foo(b); // will call foo(int*)
}
Related
std::nullptr_t is an alias for decltype(nullptr). The actual type of nullptr is unnamed. Why is std::nullptr_t an alias to an unnamed type instead of just being a built in type like int or char? That is like having the type int be unnamed and std::int_t being an alias to to decltype(1).
EDIT: This question is not a duplicate for this question, because that question was asking where std::nullptr_t was in the std namespace, and assumed that nullptr_t was a built in type which it is not. This question is simply asking why std::nullptr_t is an alias.
std::nullptr_t is its own type so that it may be implicitly converted to any pointer and pointer to member type. It cannot be a built-in type like int or even void* because it is an actual type, so nullptr is not a macro (unlike NULL) and int or void* are not implicitly convertible to other pointer types.
It is technically not named (though I'd say std::nullptr_t is its name) because it doesn't need to be named, and reserving another keyword like int or char just for that would potentially break existing code. Introducing new keywords is never easy.
Example:
static constexpr void* VOID_NULL = 0;
static constexpr int INT_NULL = 0;
int main() {
char* char_ptr = VOID_NULL; // invalid conversion
int* int_ptr = INT_NULL; // invalid conversion
}
It was introduced to fix some issues with the NULL macro. Mainly for type safety.
One issue with NULL is ambiguous calls to overloads:
void f(int*) {}
void f(std::nullptr_t) {}
int main() {
f(NULL); // ambiguous call
f(nullptr); // fine, calls the std::nullptr_t overload
}
Another issue is auto type deduction:
void f(int*) {}
int main() {
auto cloned_nullptr = nullptr;
auto cloned_NULL = NULL;
f(cloned_nullptr); // fine
f(cloned_NULL); // invalid conversion
// cloned_NULL is actually long int or similar, but not a pointer type
}
Why is std::nullptr_t an alias to an unnamed type instead of just being a built in type like int or char?
This is CWG 2689 and std::nullptr_t is considered to be a fundamental type(aka built in type), at least that seems to be the intention . This can be seen from basic.fundamental and cwg 2689:
A type denoted by cv std::nullptr_t is a distinct type. A value of type std::nullptr_t is a null pointer constant (7.3.12 [conv.ptr]). Such values participate in the pointer and the pointer-to-member conversions (7.3.12 [conv.ptr], 7.3.13 [conv.mem]). sizeof(std::nullptr_t) shall be equal to sizeof(void*).
The types described in this subclause are called fundamental types. [Note 11: Even if the implementation defines two or more fundamental types to have the same value representation, they are nevertheless different types. —end note]
Additionally, the same can be seen from type's documentation:
The C++ type system consists of the following types:
fundamental types
the type void
the type std::nullptr_t
...
(emphasis mine)
As also mentioned on the above quoted clause from cppreference, std::nullptr_t is a fundamental type(aka built in type).
I've distilled a problem that's confounded me to the minimal example shown below. Basically the gcc compiler doesn't accept NULL as a template parameter of type void*.
Is there a workaround for this?
Please note that I'm restricted to C++03.
#define NULL 0
template<typename T = void , T* = NULL>
struct Foo
{
};
typedef Foo<> FooType;
int main()
{
}
Edit: online version
There is no solution to your problem: C++03 pointer template parameters have to designate an object. Using NULL as a non-type template parameter is a feature that was added in N1905, which came out at least one year after C++03.
14.3.2 Template non-type arguments
A template-argument for a non-type, non-template template-parameter shall be one of:
an integral constant-expression of integral or enumeration type; or
the name of a non-type template-parameter; or
the address of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as & id-expression where the & is optional if the name refers to a function or array, or if the corresponding template-parameter is a reference; or
(NEW) a constant expression that evaluates to a null pointer value (4.10); or
(NEW) a constant expression that evaluates to a null member pointer value (4.11); or
a pointer to member expressed as described in 5.3.1.
One option is to declare a "null struct" with a member that you can use instead of a real NULL:
template<typename T>
struct null
{
static T value;
};
template<typename T, T* = &null<T>::value>
struct Foo
{
};
Of course, accessing null<T>::value has well-defined semantics and it won't crash; the purpose is just to have an address that is guaranteed to be different from the address of any other object.
Note that in any case, it will be impossible for you to use T = void. You can't use the null workaround with it because void is an incomplete type; and you can't cast anything to a void pointer to use as a non-type template argument.
I don't understand why adding a forward declaration for a class changes a size of its pointer to member type
#include <iostream>
using namespace std;
int main()
{
//struct CL;
//cout<<sizeof(int (CL::*)())<<endl;
struct CL{};
cout<<sizeof(int (CL::*)())<<endl;
}
output VS2013:
4
But if I uncomment the first two lines in main(), then the output is different:
16
16
So, only a simple adding a forward declaration before a definition of struct CL increases a size of a pointer to member of CL. Why? I know that a size of member function pointer depends by structure of a type (e.g. virtual functions and base classes may increase it), but why can the sizeof operator be applied to a pointer to member of an incomplete type? Or it can't? I have not found it in the Standard
The MSVC compiler uses different sizes for pointers to member functions as an optimization. This optimization violates the Standard. Kudos to Igor Tandetnik mentioning reinterpret_cast in a MSDN form post, [expr.reinterpret.cast]p10
A prvalue of type “pointer to member of X of type T1” can be
explicitly converted to a prvalue of a different type “pointer to
member of Y of type T2” if T1 and T2 are both function types
or both object types. The null member pointer value is converted to
the null member pointer value of the destination type. The result of
this conversion is unspecified, except in the following cases:
converting a prvalue of type “pointer to member function” to a different pointer to member function type and back to its original
type yields the original pointer to member value.
So there's a roundtrip guarantee, this effectively forces conforming implementations to use the same size for all pointer to member function types.
The MSVC optimization is performed if the /vmb switch is set. For the case of single inheritance, the optimised pointer to member function requires only a void*-sized storage, see The Old New Thing: Pointers to member functions are very strange animals.
If you only forward-declare the type CL and then form a pointer-to-member function, the optimization hopefully is deactivated (I could not find any documentation on that, unfortunately). Otherwise, you might get inconsistent sizes before and after the definition of CL.
By the way, you can get inconsistent sizes for enumerations in VS2010, if you forward-declare them without specifying an underlying type and later explicitly define the underlying type for the definition of the enum. This works only with language extensions activated.
Now that C++0x is almost here, I've been experimenting with it, and in particular using nullptr. I haven't been able to figure out what standard header files one is supposed to include if one needs to use it.
Any help is appreciated.
No headers should be required. It is a built-in keyword (§[lex.nullptr]).
2.14.7 Pointer literals [lex.nullptr]
pointer-literal:
nullptr
The pointer literal is the keyword
nullptr. It is a prvalue of type
std::nullptr_t. [ Note: std::nullptr_t
is a distinct type that is neither a
pointer type nor a pointer to member
type; rather, a prvalue of this type
is a null pointer constant and can be
converted to a null pointer value or
null member pointer value. See 4.10
and 4.11. —endnote]
Its type, std::nullptr_t, however, is "defined" in the header <cstddef> (§[support.types]/9).
nullptr_t is defined as follows:
namespace std {
typedef decltype(nullptr) nullptr_t;
}
The type for which nullptr_t is a synonym has the characteristics described in 3.9.1 and 4.10. [Note: Although nullptr’s address cannot be taken, the address of another nullptr_t object that is an lvalue can be taken. —endnote]
The following code
#include <stdio.h>
template <typename T, T v> class Tem
{
T t;
Tem()
{
t = v;
}
};
typedef Tem<FILE*,NULL> TemFile;
when compiled in a .mm file (Objective C++) by Xcode on MacOS X, throws the following error:
error: could not convert template argument '0' to 'FILE*'.
What's going on, please? The code in question compiled fine under MSVC. Since when is the 0 constant not a valid pointer to anything? Is this an artifact of Objective C++ (as opposed to vanilla C++)?
According to the standard, you are out of luck. There is no way to initialize a pointer argument to anything besides the address-of a global. §14.3.2/1:
A template-argument for a non-type,
non-template template-parameter shall
be one of:
an integral constant-expression of integral or enumeration type; or
the name of a non-type template-parameter; or
the address of an object or function with external linkage, including
function templates and function
template-ids but excluding non-static
class members, expressed as &
id-expression where the & is optional
if the name refers to a function or
array, or if the corresponding
template-parameter is a reference; or
a pointer to member expressed as described in 5.3.1 .
§14.3.2/5:
for a non-type template-parameter of
type pointer to object, qualification
conversions (4.4) and the
array-to-pointer conversion (4.2) are
applied. [Note: In particular, neither
the null pointer conversion (4.10) nor
the derived-to-base conversion (4.10)
are applied. Although 0 is a valid
template-argument for a non-type
template-parameter of integral type,
it is not a valid template-argument
for a non-type template-parameter of
pointer type. ]
However, Comeau accepts this invalid workaround:
typedef Tem<FILE*, (FILE *) NULL > TemFile;
And this code has a slim chance of compliance: I can't find where the standard specifically says that a default expression is used verbatim in place of a a missing argument, and I can't find a matching known defect. Anyone have a reference?
#include <stdio.h>
template <typename T, T *v = (T*) 0> class Tem
{
T t;
Tem()
{
t = v;
}
};
typedef Tem<FILE> TemFile;
For more portability, you might consider creating a bogus FILE FILE_NULL;, pass &FILE_NULL, and test for pointer-equality with that instead of zero.
Did you try something like this?
typedef Tem<FILE*,((FILE*)NULL)> TemFile;
Perhaps it's trying to figure out the type of NULL.