2017-08-14 2 views
0

Je voulais à l'origine déduire dans une classe si elle a été déclarée avec ou sans modificateur const. Comme beaucoup d'entre vous l'ont souligné, c'est la variable elle-même qui est déclarée const (et non la classe). Merci d'avoir rendu cela clair. Le message d'erreur fait maintenant totalement sens pour moi. Donc, c'est plus un problème de conception. Ce que je veux est une structure qui se comporte comme un conteneur d'accès aléatoire et fournit des fonctions comme iterator begin(){...}, const_iterator cbegin(){...}, et en particulier le value_type operator[](size_type idx){...} et quelques autres. Je veux fournir autant de fonctions que possible, que l'instance soit const ou non. Ainsi, en pratique, A a{}; a.begin(); retournera une référence non constante du type valeur de A et a.cbegin() une référence const. Alors que pour A const ac{};ac.begin() et ac.cbegin() devrait avoir le même type de référence constante. Mais probablement, ces cas d'utilisation n'ont pas de sens. Je pourrais limiter à utiliser les cas où seule la non-const a en combinaison avec itérateurs non-const sont appelable (à savoir permettre a.begin(), mais pas a.cbegin()), et ac uniquement avec const itérateurs (à savoir ac.cbegin(), mais pas ac.begin()). Est-ce que cela a du sens?GCC7 Déduire dans la même classe la présence d'un modificateur const

La raison de cette tentative bizarre est que dans mon implémentation il n'existe pas UN conteneur sous-jacent, mais deux conteneurs auxiliaires: un vecteur binaire et une séquence compressée. En fonction du contenu du vecteur de bits, je renvoie un symbole spécial ou une lettre de la séquence compressée (voir l'exemple de code étendu). Aussi, je n'utilise pas le std :: itérateur mais une propre implémentation. Note (*host)[idx + offset] renvoie un temporaire, c'est probablement pourquoi je reçois après la sortie un défaut de segmentation.

#include <cassert> 
#include <iostream> 
#include <numeric> 
#include <type_traits> 
#include <vector> 

template<typename container_t> 
struct my_iterator 
{ 
private: 
    using reference = std::conditional_t<std::is_const<container_t>::value, 
        typename container_t::const_reference, 
        typename container_t::reference>; 
    using size_type = typename container_t::size_type; 
    size_type offset = 0; 
    typename std::add_pointer_t<container_t> host{nullptr}; 
public: 
    my_iterator(container_t & host_, size_type offset_) : host{&host_}, offset{offset_} {} 
    reference operator[](typename container_t::size_type const idx) 
    { 
     return (*host)[idx + offset]; 
    } 
}; 

template<typename sequence_t> 
struct A // implements some features of the container concept 
{ 
    using const_reference = typename sequence_t::const_reference; 
    using reference = typename sequence_t::value_type; 
    using iterator = my_iterator<A>; 
    using const_iterator = my_iterator<A const>; 
    using value_type = typename sequence_t::value_type; 
    using size_type = typename sequence_t::size_type; 

    // data structures internally used to resolve random access 
    std::vector<unsigned int> bit_vector{1,0,1,0,0,0}; 
    std::vector<char> text{'h', 'w'}; 
    constexpr char static const cash = '$'; 

public: 
    // provide some container functions, like begin, end, cbegin, cend 
    iterator begin() 
    { 
     return iterator{*this, 0}; 
    } 

    const_iterator cbegin() const 
    { 
     return const_iterator{*this, 0}; 
    } 
    // ... 

    size_type rank(size_type idx) const 
    { 
     return std::accumulate(bit_vector.begin(), bit_vector.begin()+idx, 0); 
} 

constexpr reference operator[](size_type const idx) const 
{ 
    assert(idx < bit_vector.size()); 
    if (bit_vector[idx]) 
     return cash; 
    return text[idx - rank(idx)]; 
} 
}; 

int main(){ 
    /* non const usage */ 
    A<std::vector<char>> a{}; 
    auto it_a = a.begin(); 
    std::cout << it_a[0] << std::endl; 
    /* const usage */ 
    A<std::vector<char>> const a_const{}; 
    /* does not compile, because of non matching types */ 
    auto it_const_a = a_const.begin(); 
    std::cout << "it_const_a[0] = " << it_const_a[1] << std::endl; 
    /* does compile, but gives segmentation fault */ 
    auto it_const_a2 = a_const.cbegin(); 
    std::cout << "it_const_a2[0] = " << it_const_a2[1] << std::endl; 
} 
+3

'this' n'existe que dans les fonctions membres; C'est la seule situation où un objet est conscient de sa propre existence. Votre raison de vouloir cela semble un peu étrange. Si vous expliquez la connexion entre ceci et surcharger l'opérateur '[]', vous pourriez obtenir de l'aide pour résoudre votre problème réel. – molbdnilo

+0

aussi, 'A > a();' est la déclaration d'une fonction retournant 'A >'. Vous devriez écrire 'A > a;' à la place. – WindyFields

+0

Vous ne pouvez pas faire ce que vous suggérez parce que 'const' s'applique à la variable, pas à la classe. Mais cela semble définitivement être un problème X-Y. On ne sait pas exactement ce que vous recherchez, mais peut-être vous pouvez obtenir ce dont vous avez besoin avec juste 'ret_type1 operator [] (size_t);' et 'ret_type2 operator [] (size_t) const;' surcharges. – aschepler

Répondre

2

Je voudrais en déduire dans une classe si elle a été déclarée avec ou sans un modificateur const.

classes ne sont pas déclarés avec le qualificatif const. Ces qualificatifs sont pour la déclaration variables.

Il n'y a pas de this en dehors des fonctions membres non statiques, comme l'explique le message d'erreur. Les types membres (alias) d'une classe ne dépendent pas des instances et ne peuvent donc pas dépendre de la constance d'une instance.

Dans tous les cas, je suppose que vous supposez que std::iterator est un itérateur. C'est pas un itérateur. C'est une classe de base qui peut être utilisée pour éviter de répéter quelques définitions lors de l'écriture d'un itérateur (personnalisé). Et ce genre de confusion est probablement une raison pour laquelle il va être déprécié dans la prochaine version standard.