Указатель Void как аргумент шаблона в С++
Не компилируется следующее:
template<void *p>
class X {
// ...
};
int r;
int main()
{
X<&r> x;
return 0;
}
Сообщение об ошибке
x.cc:10:6: ошибка: не удалось преобразовать аргумент шаблона '& r to 'void *
Явное использование casting & r to (void *) тоже не помогает. Сообщение об ошибке становится:
x.cc:10:14: error: невозможно преобразовать аргумент шаблона '(void *) (& r) в' void *
Какая часть стандарта определяет это поведение?
Версия GCC версия gcc 5.2.1 20151003 (Ubuntu 5.2.1-21ubuntu2)
Edit:
Обратите внимание, что использование, например, int * вместо void * работает как ожидалось.
Изменить: (отвечает на себя)
Он работает не с gcc HEAD 6.0.0 20151016 (экспериментальный) при указании -std = С++ 1z, ни с неявным, ни с явным литьем в "void *".
Он работает с clang HEAD 3.8.0 (trunk 250513) и был с (по крайней мере) clang 3.6.0 (теги/RELEASE_360/final) при указании --std = С++ 1z и явно приведения к * void * ".
Без явного приведения, clang жалуется следующим образом:
x.cc:10:7: ошибка: преобразование из 'int *' в 'void *' недопустимо в преобразованном постоянном выражении
Ответственность за исправление этой ошибки в спецификации языка С++ - N4268, который уже реализуется.
Ответы
Ответ 1
Обычно для любого указателя на void*
допускается преобразование.
[С++ 11, 4.10/2] PRvalue типа "указатель на cv T", где T является тип объекта, может быть преобразован в prvalue типа "указатель на cv void". Результат преобразования "указателя на cv T" в "указатель на cv void" указывает на начало места хранения, где объект типа T, как будто объект является наиболее производным объектом (1.8) of тип T (то есть не подобъект базового класса). Значение нулевого указателя преобразуется в значение нулевого указателя для типа адресата.
Однако для аргументов шаблона непигового типа заданы определенные преобразования:
[С++ 11, 14.3.2/5] Следующие преобразования выполняются для каждого выражение, используемое в качестве аргумента шаблона, не относящегося к типу. Если не-тип template-argument не может быть преобразован в тип соответствующего шаблон-параметр, тогда программа плохо сформирована.
[...]
- для не-типа шаблона-параметра указателя типа на объект, квалификационные преобразования (4.4) и преобразование массива в указатель (4.2); если аргумент template имеет тип std:: nullptr_t, применяется преобразование нулевого указателя (4.10). [...]
Попутно, мы можем рассуждать, что это преобразование просто не разрешено.
Ответ 2
Я не могу процитировать вас главу и стихи с моей головы (правки приветствуются), но то, что вы пытаетесь сделать, не разрешено в С++.
Параметры шаблона должны быть известны во время компиляции. Указатели разрешаются только во время соединения, если:
-
они по умолчанию используют = nullptr
в списке аргументов шаблона.
-
они являются указателями на функцию-члены (которые известны во время компиляции, поскольку они просто смещения).
например, это скомпилирует:
template<void * = nullptr>
class X {
// ...
};
int r;
int main()
{
X<nullptr> x;
return 0;
}