Kopya oluşturucuda C ++ ad alanı çakışması


33

Takip koduna sahibim:

namespace A {
    struct Foo {
        int a;
    };
}

struct Foo {
    int b;
};

struct Bar : public A::Foo {
    Bar(Foo foo) {
        c = foo.b;
    }
    int c;
};

A :: Foo'nun b adlı bir üyesi olmadığı için C ++ derleyicileri "c = foo.b" dosyasında şikayetçi olur. Bar parametresinin türünü :: Foo ile değiştirirsem çalışır.

Benim sorum bu davranışın ardındaki mantıklı şey (sanırım miras Bar'ın A ad alanına girmesini sağlıyor, ancak bu teoriyi destekleyen herhangi bir belge bulamıyorum.


8
Ben düşünüyorum 's argümanı bağımlı arama ilgili. Ben dil standardını referans cevaplar peşinde olduğunu düşünüyorum gibi "dil-avukat" etiketledim. Ve çok iyi bir ilk soru! Her şeyi değerli kılıyor.
Bathsheba

Başka bir yapıdan miras Aalıp almadığınızı görebileceğiniz ad alanına girmez . O zaman belirsizlik yoktur. Daha miras gibidir herşeyi ekler için çözünürlüğünü dahil etmekBarAA::FooBarFooA::Foo . Üzgünüm, daha kesin ifade edemiyorum.
n314159

@Bathsheba Şablonlarda işlev adlarını (veya işlev şablonları adlarını) veya bağımlı adları bulmak için bağımsız değişken türüne bağımlı ad araması mı demek istediniz?
curiousguy

Yanıtlar:


22

Her sınıfın kendisine üye olarak adı eklenir. Böylece adlandırabilirsinizA::Foo::Foo . Buna enjekte edilen sınıf adı denir.

[sınıf]

2 Sınıf adı göründükten hemen sonra bildirildiği kapsama bir sınıf adı eklenir. Sınıf adı da sınıfın kapsamına eklenir; buna enjekte edilen sınıf adı denir. Erişim kontrolü amacıyla, enjekte edilen sınıf adı herkese açık bir üye adı gibi muamele görür.

[Basic.lookup]

3 Bir sınıfın enjekte edilen sınıf adı, ad gizleme ve arama amacıyla bu sınıfın bir üyesi olarak kabul edilir.

Bağımsız değişken türünün niteliksiz ad araması sınıf kapsamında başladığı için, buradaki Barherhangi bir üyeyi hesaba katmak için temel sınıfının kapsamına devam edecektir. Ve bulacakA::Foo::Foo bir tür adı olarak .

Global tür adını kullanmak istiyorsanız, onu çevreleyen (global) ad alanına göre nitelendirin.

Bar(::Foo foo) {
    c = foo.b;
}

Hangi enjekte sınıf adı görünmez bir kapsamda tam nitelikli arama yapıyor.

Bir takip "neden" sorusu için bkz.


5
@TedLyngmo - ADL, işlev çağrılarıyla gerçekleşir, bu belirli bölümlerle ilgili değildir.
StoryTeller - Unslander Monica

Oki, okuyordum ve emin değildim. Teşekkürler!
Ted Lyngmo

3
Bu çok eğlenceli derivasyonlarında struct Bar:: A::Foo::Foo::Foo::Foo::Foo {}; ama bağlamlar vardırA::Foo::Foo yapıcı atar ve böylece orada birçok olarak eklemeye devam edemez Fooistediğiniz kadar. Bu, bir fonksiyonunu çağırabilir gerçeğine benzer (ama tamamen farklı bir mekanizma ile) 'dir fbu şekilde: (************f)().
AProgrammer


Bu cevap kesinlikle "ne" yi açıklar. "Neden" i eklemek daha iyi olabilir mi? İçinde olduğu gibi, bu kuralın amacı nedir? Hangi kullanım durumlarını iyileştirir veya mümkün kılar?
davidbak

2

Tam bir cevap değil, sadece Bargirdiği kodu (derlediği için) gösteren kod namespace A. Buradan miras alırken A::Foo1, Foobu mirasın Bargirmesine izin verirse , belirsizliği ile ilgili bir sorun olmadığını görebilirsiniz A.

namespace A {
    struct Foo {
        int a;
    };

    struct Foo1 {
        int a;
    };
}

struct Foo {
    int b;
};

struct Bar : public A::Foo1 {
    Bar(Foo foo) {
        c = foo.b;
    }
    int c;
};
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.