const_cast no modelo. Existe um modificador inconsciente?
-
19-09-2019 - |
Pergunta
Eu tenho uma classe de modelo como esta:
template<T>
class MyClass
{
T* data;
}
Às vezes, quero usar a classe com um tipo T constante da seguinte maneira:
MyClass<const MyObject> mci;
Mas eu quero modificar os dados usando const_cast<MyObject*>data
(não é importante por que, mas MyClass
é uma classe de ponteiro inteligente de contagem de referência que mantém a contagem de referência nos próprios dados. MyObject
é derivado de algum tipo que contém a contagem. Os dados não devem ser modificados, mas a contagem deve ser modificada pelo ponteiro inteligente.).
Existe uma maneira de remover a constividade de T
? Código fictício:
const_cast<unconst T>(data)
?
Solução
A maneira mais simples aqui seria tornar a contagem de referência mutável.
No entanto, se você estiver interessado em como funcionaria com o const_cast
, então reimplementar o impulso remove_const
deve ser bastante simples:
template <class T>
struct RemoveConst
{
typedef T type;
};
template <class T>
struct RemoveConst<const T>
{
typedef T type;
};
const_cast<typename RemoveConst<T>::type*>(t)->inc();
Outras dicas
Você tem a resposta. const_cast funciona em ambas as direções:
char* a;
const char* b;
a = const_cast<char*>(b);
b = const_cast<const char*>(a); // not strictly necessarily, just here for illustration
Quanto ao seu problema específico, você considerou a palavra -chave mutável? Ele permite que uma variável de membro seja modificada dentro de um método const.
class foo {
mutable int x;
public:
inc_when_const() const { ++x; }
dec_when_const() const { --x; }
};
Torne a contagem de referência mutável na classe gerenciada pelo seu ponteiro intrusivo. Isso é totalmente razoável e reflete a "constituição lógica" exatamente corretamente - ou seja, alterar a contagem de referência do objeto não reflete nenhuma alteração no estado do próprio objeto. Em outras palavras, a contagem de referência não faz parte logicamente do objeto-o objeto é um local conveniente para armazenar esses dados semi-relacionados.
Se você pode usar o Boost, a biblioteca de traços de tipo fornece o remove_const Metafunção que faz isso.
Aqui está o meu C ++ 11 unconst
função template
.
Se você o usar, você está flertando com comportamento indefinido. Você tem sido avisou.
// on Ubuntu (and probably others) compile and test with
// g++ -std=c++11 test.c && ./a.out ; echo $?
template < class T > T & unconst ( T const & t ) {
return const_cast < T & > ( t ) ;
}
// demonstration of use
struct {
const int n = 4;
} s;
int main () {
unconst ( s.n ) = 5;
return s.n;
}