2011-10-13 2 views
4

Le code suivant compile et fonctionne sur G ++ 4.4.0 et MS VC2008 Express."const const T" dans le modèle

#include <iostream> 

template<typename T> struct A{ 
protected: 
    T v; 
public: 
    const T get() const{ 
     return v; 
    } 

    A(T v_) 
    :v(v_){ 
    } 
}; 

class B: public A<const int*>{ 
public: 
    void doSomething() const{ 
     const int* tmp = get(); 
     std::cout << *tmp << std::endl; 
    } 

    B(const int* p) 
    :A<const int*>(p){ 
    } 
}; 

int main(int argc, char** argv){ 
    int a = 134; 
    B b(&a); 
    const B& c = b; 
    b.doSomething(); 
    c.doSomething(); 
    return 0; 
} 

Cependant, si je comprends bien l'aide A<const int*> devrait aboutir à const const int* A::get() const;. Et je suis sûr que je n'ai rien vu de tel dans le vrai code. Est-ce que l'utilisation du modèle est "légale"?

Sinon, quelles sont les alternatives? Dans mon code, j'ai besoin d'une classe de template qui fournit deux méthodes "getter" (const/non-const), et peut prendre un "const int *" comme type. Quelque chose comme ceci:

template<typename T> struct A{ 
protected: 
    T v; 
public: 
    const T get() const{ 
     return v; 
    } 

    T get(){ 
     return v; 
    } 

    A(T v_) 
    :v(v_){ 
    } 
}; 

Des idées?

+0

On dirait que vous avez un «besoin constant»;) – bobobobo

Répondre

5

Si T = const int *, alors const T est const int * const.

+0

Bon, si j'ai manqué quelque chose comme * ça *, alors je suppose que je dois faire une pause. Merci pour la réponse rapide. – SigTerm

+5

@SigTerm: ... et c'est pourquoi j'aime mettre 'const' sur la droite ... Ajouter' const' à 'int const *' est 'int const * const', ce qui est simple à raisonner sur :) –

3

Nous pouvons traduire

const int * 

dans

int const * 

Un pointeur vers un int constant. Lorsque vous avez T = int *, ce que vous avez avec const T est:

int * const 

Ce qui signifie, un pointeur constant à un int.

Donc, dans votre cas avec T = const int *, qui est int const *, ce que vous avez avec const T est:

int const * const 

Ce qui signifie un pointeur constant à un int constant. Ce qui est légal.

Si ce n'est pas le comportement souhaité, vous pouvez avoir une spécialisation partielle, comme:

template<typename T> struct A<const T>{ 
//here comes different implementation for the case where A template is 
//initialized with a const type. 
2

It's fine pour ce faire

struct Foo {}; 
typedef const Foo CFoo; 

const CFoo c; 
+1

Il compile ne veut pas dire que c'est légal. – Mat

4

Il est pas un problème d'avoir plusieurs const qualificatifs: ils Pliez simplement ensemble.

Cependant, vous l'interprétez mal, car vous ne le placez pas correctement (et c'est dommage que la syntaxe le permette).

Si vous placez le constaprès le le type qu'il qualifie, vous vous rendrez compte que vous étiez en train de le lire incorrectement.

Un const TT est const int* n'est PAS const const int* = const int*.

Si vous écrivez correctement: T constT est int const*, vous le lirez int const* const, qui est un pointeur const à un const int, et non pas un pointeur sur un const int.

0

const int const * est un code légal et signifie un pointeur constant vers une valeur constante. Votre code se traduit probablement par la même expression.

+0

Non, c'est faux. Ce que vous avez est un pointeur non-const vers const int (si votre expression est légale). – Mat

1

Toutes les autres réponses se tient-il constness, si vous vouliez un type non qualifié, vous pouvez utiliser un crâne-Duggery petit modèle ..

template <typename T> 
struct remove_const 
{ 
    typedef T type; 
}; 

template <typename T> 
struct remove_const<T*> 
{ 
    typedef T* type; 
}; 

template <typename T> 
struct remove_const<const T> 
{ 
    typedef T type; 
}; 

template <typename T> 
struct remove_const<const T*> 
{ 
    typedef T* type; 
}; 

template <typename T> 
void foo (T& b) 
{ 
    typename remove_const<T>::type a = b; 
} 

Si vous passez un pointeur const-foo, vous aurez voir que a a le type non-const et donc l'attribution échoue.