hata: xxx'i xxx 'niteleyicilerinin' bu 'argümanı olarak geçirme


457
#include <iostream>
#include <set>

using namespace std;

class StudentT {

public:
    int id;
    string name;
public:
    StudentT(int _id, string _name) : id(_id), name(_name) {
    }
    int getId() {
        return id;
    }
    string getName() {
        return name;
    }
};

inline bool operator< (StudentT s1, StudentT s2) {
    return  s1.getId() < s2.getId();
}

int main() {

    set<StudentT> st;
    StudentT s1(0, "Tom");
    StudentT s2(1, "Tim");
    st.insert(s1);
    st.insert(s2);
    set<StudentT> :: iterator itr;
    for (itr = st.begin(); itr != st.end(); itr++) {
        cout << itr->getId() << " " << itr->getName() << endl;
    }
    return 0;
}

Çizgide:

cout << itr->getId() << " " << itr->getName() << endl;

Bir hata veriyor:

../main.cpp:35: hata: 'const StudentT' ifadesinin 'int StudentT :: getId ()' argümanı olarak 'niteleyicileri' niteleyicileri atar

../main.cpp:35: hata: 'const StudentT'i' std :: string StudentT :: getName () 'argümanı olarak' niteleyiciler 'niteleyicileri atar

Bu kodda yanlış olan ne? Teşekkür ederim!


13
Kod snippet'inizdeki 35. satır nerede?
Silico'da

118
Keşke GCC bu hata mesajını geliştirir, örneğin "niteleyicileri atar" -> "const doğruluğunu
bozar

13
@ jfritz42: Atılan dava için kafa karıştırıcı olurduvolatile
PlasmaHH

3
@ PlazmaHH hata mesajı "kopma doğruluğunu keser" ve "geçici doğruluğu keser" olarak bölünür. Şimdi, pek çok insan bir şeyin uçucu olduğunu doğru
Caleth

Yanıtlar:


524

İçindeki nesneler std::setolarak depolanır const StudentT. Bu nedenle getId(), constnesneyle çağrılmaya çalıştığınızda derleyici bir sorun algılar, temel olarak const nesnesinde const olmayan bir üye işlevini çağırırsınız , çünkü const üyesi olmayan işlevler nesneyi değiştirmemek için NO PROMISE yapar; böylece derleyici, nesneyi değiştirmeye çalışabilecek güvenli bir varsayımda getId()bulunacak, ancak aynı zamanda nesnenin sabit olduğunu da fark edecektir; bu nedenle const nesnesini değiştirme girişimleri bir hata olmalıdır. Bu nedenle derleyici bir hata mesajı oluşturur.

Çözüm basittir: işlevleri şu şekilde yapılandırın:

int getId() const {
    return id;
}
string getName() const {
    return name;
}

Şimdi Arayabileceğin için bu gereklidir getId()ve getName()olarak const nesneler üzerinde:

void f(const StudentT & s)
{
     cout << s.getId();   //now okay, but error with your versions
     cout << s.getName(); //now okay, but error with your versions
}

Bir sidenote olarak şunları uygulamanız gerekir operator<:

inline bool operator< (const StudentT & s1, const StudentT & s2)
{
    return  s1.getId() < s2.getId();
}

Not parametreleri artık constreferanstır.


3
Böyle açık bir açıklama. Teşekkürler. Ama son kod pasajınızı merak ediyorum. Neden function parametresinde başvuru kullanılır? const StudentT & s1, const StudentT & s2?
Rafael Adel

2
@RafaelAdel: Gereksiz kopyadan kaçınmak için başvuruyu kullanırsınız ve constişlevin nesneyi değiştirmesi gerekmediğinden, bunu constderleme zamanında uygular.
Nawaz

90

Sınıf örneğini değiştirmeyen üye işlevleri şu şekilde bildirilmelidir const:

int getId() const {
    return id;
}
string getName() const {
    return name;
}

Ne zaman "niteleyicileri atar" görürseniz, constya da bahsediyor volatile.


2
@Fred - Sınıf işlevlerini değiştirmeyen üye işlevlerine const değiştiricileri eklemenin kesinlikle bir gereklilik olduğunu düşünüyor musunuz? Bu durumda hatanın başka bir nedeni var mı? Şüpheliyim çünkü yazdığım çoğu alıcıda, ona const değiştiricileri eklemiyorum.
Mahesh

@Mahesh: Evet, const doğruluğunun bir parçası . constBuradan nereden geldiğinden emin değilim , ancak setörneğin değişmesini ve böylece seti geçersiz kılmasını önlemek için yineleyiciden bir const referansı döndürdüğünden şüpheleniyorum .
Fred Larson

@ Mahesh: Kod incelememi geçemezdim. Bana "anlaşılabilir" diye değinen bir iş arkadaşım var. 8v) Değişim o foo obj;kadar const foo obj;bir kez ve ne olduğunu görün. Veya consta foo.
Fred Larson

3
@Mahesh: Dediğim gibi - a öğesindeki öğeler setdeğiştirilirse, düzen bozulabilir ve bu küme artık geçerli değildir. Bir map, sadece anahtar const. Birinde set, tüm nesne gerçekten anahtardır.
Fred Larson

1
@Mahesh: const gereklidir aksi takdirde onları const nesneleriyle çağıramazsınız. cevabımdaki işlevi gör f().
Nawaz

5

Aslında C ++ standardı (yani C ++ 0x taslağı ) diyor ki (bunu bana işaret ettiği için @ Xeo & @Ben Voigt'e tnx):

23.2.4 İlişkili kaplar
5 Set ve çoklu ayar için değer türü, anahtar türüyle aynıdır. Harita ve çoklu harita için çifttir. İlişkilendirilebilir bir kaptaki anahtarlar değiştirilemez. Bir ilişkisel kabın
6 yineleyicisi, çift yönlü yineleyici kategorisindedir. Değer türünün anahtar türüyle aynı olduğu ilişkilendirilebilir kapsayıcılar için, hem yineleyici hem de const_iterator sabit yineleyicilerdir. Yineleyici ve const_iterator öğelerinin aynı tür olup olmadığı belirtilmez.

VC ++ 2008 Dinkumware uygulaması hatalı.


Eski cevap:

Bu hatayı aldınız çünkü std lib'in bazı uygulamalarında set::iteratoraynıdır set::const_iterator.

Örneğin, libstdc ++ (g ++ ile birlikte gönderilir) ( kaynak kodun tamamı için buraya bakın ):

typedef typename _Rep_type::const_iterator            iterator;
typedef typename _Rep_type::const_iterator            const_iterator;

SGI dokümanlarında şunları belirtiyor:

iterator       Container  Iterator used to iterate through a set.
const_iterator Container  Const iterator used to iterate through a set. (Iterator and const_iterator are the same type.)

Öte yandan VC ++ 2008 Express kodları set::iterators üzerinde const olmayan yöntemleri çağırdığınız şikayet etmeden derler .


2

Daha ayrıntılı bir örnek vereyim. Aşağıdaki yapıya gelince:

struct Count{
    uint32_t c;

    Count(uint32_t i=0):c(i){}

    uint32_t getCount(){
        return c;
    }

    uint32_t add(const Count& count){
        uint32_t total = c + count.getCount();
        return total;
    }
};

resim açıklamasını buraya girin

Yukarıda gördüğünüz gibi, IDE (CLion) ipuçları verecektir Non-const function 'getCount' is called on the const object. Yöntemde add countconst nesnesi olarak bildirilir, ancak yöntem getCountconst yöntemi değildir, bu nedenle count.getCount()içindeki üyeleri değiştirebilir count.

Aşağıdaki gibi derleme hatası (derleyicimdeki temel mesaj):

error: passing 'const xy_stl::Count' as 'this' argument discards qualifiers [-fpermissive]

Yukarıdaki sorunu çözmek için şunları yapabilirsiniz:

  1. yöntemi uint32_t getCount(){...}olarak değiştir uint32_t getCount() const {...}. Yani count.getCount()üyeleri değiştirmeyecek count.

veya

  1. değiştirmek uint32_t add(const Count& count){...}için uint32_t add(Count& count){...}. Yani countiçindeki üyeleri değiştirmeyi umursamıyorum.

Soruna gelince, std :: set içindeki nesneler const StudentT olarak saklanır, ancak yöntem getIdve getNameconst değildir, bu nedenle yukarıdaki hatayı verirsiniz.

Ayrıca bu soruyu bir sınıfın işlev bildiriminde son olarak 'const' anlamı da görebilirsiniz. daha fazla ayrıntı için.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.