Из моего класса-оболочки Pointer<Base>
Я бы хотел вернуть только указатели на const: Base const *
.
При приведении Pointer<Base>
к Derived const *
я получаю ошибку компиляции:
ошибка C2440: «static_cast»: «Указатель» не может быть преобразован в «const Derived *»
(перевод с немецкого VS2012)
struct Base { };
struct Derived : public Base { };
template <typename T>
class Pointer {
public:
Pointer(T *t = nullptr) : p(t) { }
//operator T*() { return p; }
operator T const *() const { return p; }
template <typename U>
inline U staticCast() const { return static_cast<U>(d); }
private:
T *p;
};
int main(int argc, char *argv[]) {
Derived d;
Pointer<Base> p(&d);
Derived const *pd = static_cast<Derived const *>(p);
}
Если включить преобразование operator T*() { return p; }
, оно будет работать.
Почему static_cast
не использует оператор преобразования констант?
Или, точнее, с
Derived const *pd = static_cast<Derived const *>(static_cast<Base const *>(p));
работает:
Почему static_cast
может неявно приводиться к Base *
, но не к Base const *
, хотя последнего достаточно для целевого типа приведения?
Стандарт гласит :
Если существует неявная последовательность преобразования из выражения в new_type или если при разрешении перегрузки для прямой инициализации объекта или ссылки типа new_type из выражения найдется хотя бы одна жизнеспособная функция, то static_cast (expression) возвращает мнимую переменную Temp инициализируется как будто с помощью new_type Temp (выражение); это может включать неявные преобразования , вызов конструктора new_type или вызов пользовательского оператора преобразования .
[Акцент мной]
Обход
Поскольку это похоже на ошибку VisualStudio, вместо этого я буду использовать обходной путь с помощью шаблонной функции-члена staticCast()
(см. Пример кода выше), которая будет использоваться следующим образом:
Derived const *pd = p.staticCast<Derived const *>();
Чтобы разрешить только приведение к U const *
, используйте SFINAE:
template <typename U>
struct is_pointer_to_const
{
static const bool value = std::is_pointer<U>::value
&& std::is_const<typename std::remove_pointer<U>::type >::value;
};
template <typename U>
inline U staticCast(typename std::enable_if<is_pointer_to_const<U>::value >::type* = 0) const
{ return static_cast<U>(d); }
template <typename U>
inline U staticCast(typename std::enable_if<!is_pointer_to_const<U>::value >::type* = 0) const
{ static_assert(false, "Type is not a pointer to const"); return U(); }