The following does not compile:
template<void *p>
class X {
// ...
};
int r;
int main()
{
X<&r> x;
return 0;
}
The error message is
x.cc:10:6: error: could not convert template argument ‘& r’ to ‘void*’
Explicitly casting &r to (void *) doesn't help either. The error message becomes:
x.cc:10:14: error: could not convert template argument ‘(void*)(& r)’ to ‘void*’
Which part of the standard specifies that behaviour? The GCC version is gcc version 5.2.1 20151003 (Ubuntu 5.2.1-21ubuntu2)
Edit:
Please note that using e.g. int * instead of void * works as expected.
Edit: (answering myself)
It does not work with gcc HEAD 6.0.0 20151016 (experimental) when specifying -std=c++1z, neither with implicit nor with explicit casting to "void *".
It does work with clang HEAD 3.8.0 (trunk 250513) and has been since (at least) clang 3.6.0 (tags/RELEASE_360/final) when specifying --std=c++1z and explicitly casting to *void *". Without the explicit cast, clang complains as follows:
x.cc:10:7: error: conversion from 'int *' to 'void *' is not allowed in a converted constant expression
Responsible for fixing this bug in the c++ language specification is N4268 which clang already implements.
The void pointer in C is a pointer that is not associated with any data types. It points to some data location in the storage. This means that it points to the address of variables. It is also called the general purpose pointer.
In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
A template has only one type, but a specialization is needed for pointer, reference, pointer to member, or function pointer types. The specialization itself is still a template on the type pointed to or referenced.
After declaration, we store the address of variable 'data' in a void pointer variable, i.e., ptr. Now, we want to assign the void pointer to integer pointer, in order to do this, we need to apply the cast operator, i.e., (int *) to the void pointer variable.
Normally, there is a conversion allowed for any pointer to void*
.
[C++11, 4.10/2] A prvalue of type “pointer to cv T,” where T is an object type, can be converted to a prvalue of type “pointer to cv void”. The result of converting a “pointer to cv T” to a “pointer to cv void” points to the start of the storage location where the object of type T resides, as if the object is a most derived object (1.8) of type T (that is, not a base class subobject). The null pointer value is converted to the null pointer value of the destination type.
However, for non-type template arguments, certain conversions are specified:
[C++11, 14.3.2/5] The following conversions are performed on each expression used as a non-type template-argument. If a non-type template-argument cannot be converted to the type of the corresponding template-parameter then the program is ill-formed.
[...]
— 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; if the template-argument is of type std::nullptr_t, the null pointer conversion (4.10) is applied. [...]
By omission, we can reason this conversion is simply not allowed.
I can't quote you the chapter and verse off the top of my head (edits are welcome), but what you are trying to do is not allowed in c++.
Template parameters must be known at compile time. Pointers are only resolved at link time unless:
they are defaulted using = nullptr
in the template argument list.
they are member function pointers (which are known at compile time since they are merely offsets).
for example, this will compile:
template<void * = nullptr>
class X {
// ...
};
int r;
int main()
{
X<nullptr> x;
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With