Reputation: 1262
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.
Upvotes: 11
Views: 2868
Reputation: 69892
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;
}
Upvotes: 1
Reputation: 11
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.
Upvotes: 1