const_casting 容器的元素类型
const_casting element type of container
是否有一种有效且安全的方法将 std::vector<const Point*>&
转换为 std::vector<Point*>&
?
执行 reinterpret_cast<std::vector<Point*>&>(constvec)
可能会正常工作,但可能是未定义的行为。
唯一的标准选项似乎是构建一个新的 std::vector<Point*>
并手动添加每个 const_cast
ed 元素,但程序会不必要地为其分配内存。
编辑:
该程序看起来像这样(简化):
class A {
private:
int some_data[10];
public:
template<typename Callback>
void algo(Callback callback) const {
std::vector<const int*> values { &some_data[0], &some_data[5], &some_data[3] };
// Class is const-correct internally, so only have const access to data here.
// Making it mutable is not easily possible in the real code,
// as there are constructs similar to iterator/const_iterator in the class hierarchy.
callback(values);
}
template<typename Callback>
void algo(Callback callback) {
// Hack to avoid copying the entire algorithm implementation
auto cb = [&](const std::vector<const int*>& vec) {
callback(....); // <--- should be const std::vector<int*>
}
static_cast<const A*>(this)->algo(cb);
}
};
另一种选择是在非 const 变体中实现算法,然后 const_cast<A&>(*this).algo()
用于 const 变体。但这似乎更危险,因为 A
对象可能已创建为 const (const A a;
) 然后它是 UB.
除了 std::vector
是一个标准库 class 之外,类型 vector<Foo*>
和 vector<Foo const*>
可能有不同的专门化和不同的大小。因此,虽然 reinterpret_cast
通常会起作用,但它在形式上是未定义的行为。无论如何,需要 reinterpret_cast
(除了在某些 C 风格的上下文中,例如 Windows API 级别的编程)通常是一个强烈的信号,表明一个人走错了路。
如果有人在 const
和非 const
版本中都需要一种方法的重要代码,一种解决方案是遵循普通函数,例如一个 static
成员函数。
要做到这一点,有一些支持机器很方便:
struct Mutable{};
struct Const{};
template< class Constness, class Type >
struct With_t;
template< class Type > struct With_t<Mutable, Type>{ using T = Type; };
template< class Type > struct With_t<Const, Type>{ using T = Type const; };
template< class Constness, class Type >
using With = typename With_t<Constness, Type>::T;
然后你可以这样写classes:
class Foo
{
private:
int something_;
template< class Constness >
static auto p( With<Constness, Foo>* that )
-> With<Constness, int>*
{ return &that->something_; } // In the real world some non-trivial code here.
public:
auto p() -> int* { return p<Mutable>( this ); }
auto p() const -> int const* { return p<Const>( this ); }
Foo( int const value ): something_( value ) {}
};
template<class A, class B>
struct as_const_as { using type=B; }
template<class A, class B>
struct as_const_as<const A, B> { using type=const B; }
template<class A, class B>
using as_const_as_t=typename as_const_as<A,B>::type;
private:
template<class Self, class Callback>
static void algo(Self* self, Callback callback) {
// code using self instead of this
using int_t = as_const_as_t<Self, int>; // const or not depending on self
}
public:
template<class Callback>
void algo(Callback callback) {
algo( this, callback );
}
template<class Callback>
void algo(Callback callback) const {
algo( this, callback );
}
现在我们有两个外部方法algo
,一个static
方法将自己的类型作为模板类型,可以是const
也可以不是。
是否有一种有效且安全的方法将 std::vector<const Point*>&
转换为 std::vector<Point*>&
?
执行 reinterpret_cast<std::vector<Point*>&>(constvec)
可能会正常工作,但可能是未定义的行为。
唯一的标准选项似乎是构建一个新的 std::vector<Point*>
并手动添加每个 const_cast
ed 元素,但程序会不必要地为其分配内存。
编辑: 该程序看起来像这样(简化):
class A {
private:
int some_data[10];
public:
template<typename Callback>
void algo(Callback callback) const {
std::vector<const int*> values { &some_data[0], &some_data[5], &some_data[3] };
// Class is const-correct internally, so only have const access to data here.
// Making it mutable is not easily possible in the real code,
// as there are constructs similar to iterator/const_iterator in the class hierarchy.
callback(values);
}
template<typename Callback>
void algo(Callback callback) {
// Hack to avoid copying the entire algorithm implementation
auto cb = [&](const std::vector<const int*>& vec) {
callback(....); // <--- should be const std::vector<int*>
}
static_cast<const A*>(this)->algo(cb);
}
};
另一种选择是在非 const 变体中实现算法,然后 const_cast<A&>(*this).algo()
用于 const 变体。但这似乎更危险,因为 A
对象可能已创建为 const (const A a;
) 然后它是 UB.
除了 std::vector
是一个标准库 class 之外,类型 vector<Foo*>
和 vector<Foo const*>
可能有不同的专门化和不同的大小。因此,虽然 reinterpret_cast
通常会起作用,但它在形式上是未定义的行为。无论如何,需要 reinterpret_cast
(除了在某些 C 风格的上下文中,例如 Windows API 级别的编程)通常是一个强烈的信号,表明一个人走错了路。
如果有人在 const
和非 const
版本中都需要一种方法的重要代码,一种解决方案是遵循普通函数,例如一个 static
成员函数。
要做到这一点,有一些支持机器很方便:
struct Mutable{};
struct Const{};
template< class Constness, class Type >
struct With_t;
template< class Type > struct With_t<Mutable, Type>{ using T = Type; };
template< class Type > struct With_t<Const, Type>{ using T = Type const; };
template< class Constness, class Type >
using With = typename With_t<Constness, Type>::T;
然后你可以这样写classes:
class Foo
{
private:
int something_;
template< class Constness >
static auto p( With<Constness, Foo>* that )
-> With<Constness, int>*
{ return &that->something_; } // In the real world some non-trivial code here.
public:
auto p() -> int* { return p<Mutable>( this ); }
auto p() const -> int const* { return p<Const>( this ); }
Foo( int const value ): something_( value ) {}
};
template<class A, class B>
struct as_const_as { using type=B; }
template<class A, class B>
struct as_const_as<const A, B> { using type=const B; }
template<class A, class B>
using as_const_as_t=typename as_const_as<A,B>::type;
private:
template<class Self, class Callback>
static void algo(Self* self, Callback callback) {
// code using self instead of this
using int_t = as_const_as_t<Self, int>; // const or not depending on self
}
public:
template<class Callback>
void algo(Callback callback) {
algo( this, callback );
}
template<class Callback>
void algo(Callback callback) const {
algo( this, callback );
}
现在我们有两个外部方法algo
,一个static
方法将自己的类型作为模板类型,可以是const
也可以不是。