Birden çok argüman alan açık oluşturucu


88

Birden fazla argümana explicitsahip bir kurucu yapmanın herhangi (yararlı) bir etkisi var mı?

Misal:

class A {
    public:
        explicit A( int b, int c ); // does explicit have any (useful) effect?
};

Yanıtlar:


120

C ++ 11'e kadar, evet, explicitçok argümanlı bir kurucuda kullanmak için bir neden yok .

Bu, başlatıcı listeleri nedeniyle C ++ 11'de değişir. Temel olarak, bir başlatıcı listesiyle kopya başlatma (ancak doğrudan başlatma değil), kurucunun işaretlenmemesini gerektirir explicit.

Misal:

struct Foo { Foo(int, int); };
struct Bar { explicit Bar(int, int); };

Foo f1(1, 1); // ok
Foo f2 {1, 1}; // ok
Foo f3 = {1, 1}; // ok

Bar b1(1, 1); // ok
Bar b2 {1, 1}; // ok
Bar b3 = {1, 1}; // NOT OKAY

5
Bu cevabın "Bunu neden isteyeyim ki" veya "Bu ne zaman yararlıdır" açıklamasıyla daha iyi olacağını düşünüyorum.
MateuszL

@MateuszL Edgar'ın cevabı, neden yararlı olabileceğine dair muhtemelen en iyi argümanı veriyor (ve tartışmalı bir şekilde onaylamayı hak ediyor). Orada olmasının nedeni , basitçe için var olan anlambilimin mantıksal uzantısı olmasıdır explicit. Ben şahsen çoklu argümanlar oluşturucular yapmakla uğraşmam explicit.
Sneftel

31

Küme ayracı başlatma için yanılabilirsiniz (örneğin dizilerde)

struct A {
        explicit A( int b, int c ) {}
};

struct B {
         B( int b, int c ) {}
};

int main() {
    B b[] = {{1,2}, {3,5}}; // OK

    A a1[] = {A{1,2}, A{3,4}}; // OK

    A a2[] = {{1,2}, {3,4}}; // Error

    return 0;
}

24

@StoryTeller ve @Sneftel'in mükemmel yanıtları ana nedendir. Bununla birlikte, IMHO, kodda daha sonra yapılacak değişiklikleri doğrulamanın bir parçası olarak bu mantıklı (en azından ben yaparım). Örneğinizi düşünün:

class A {
    public:
        explicit A( int b, int c ); 
};

Bu kod doğrudan fayda sağlamaz explicit.

Bir süre sonra, için varsayılan bir değer eklemeye karar verirsiniz c, yani şu olur:

class A {
    public:
        A( int b, int c=0 ); 
};

Bunu yaparken, cparametreye odaklanıyorsunuz - geriye dönüp bakıldığında, varsayılan bir değere sahip olması gerekir. AKendisinin örtük olarak inşa edilip edilmeyeceğine odaklanmak zorunda değilsiniz . Maalesef bu değişiklik explicittekrar alakalı hale geliyor .

Yani, bir ctor olduğunu iletmek explicitiçin, yöntemi ilk yazarken bunu yapmak faydalı olabilir.


Ancak, bakımcının bu temerrüdü ekleyip sonucun bir dönüştürücü kurucu olarak mevcut olması gerektiği sonucuna varması durumu ne olacak? Şimdi zorunda kaldırmak olduğunu explicitsonsuza dek var oldu ve teknik destek söz konusu değişiklikle ilgili görüşmeleri ile sular altında kalacak ve harcama saat açıklayan explicitsadece gürültü oldu ve kaldırma o zararsızdır. Kişisel olarak geleceği tahmin etmekte pek iyi değilim; Şu anda bir arayüzün nasıl görünmesi gerektiğine karar vermek yeterince zor .
Pete Becker

@PeteBecker Bu iyi bir nokta. Şahsen, iki durumun asimetrik olduğunu ve parametreleri varsayılan yapmanın (veya kaldırmanın) yanlışlıkla sınıfı örtük olarak inşa edilebilir hale getirmenin ve daha sonra aynı zamanda geçmişe bakıldığında böyle olması gerektiğini anlamanın çok daha yaygın olduğunu düşünüyorum. Bununla birlikte, bunlar "yumuşak" düşüncelerdir ve insanlar / projeler / vb. Arasında değişiklik gösterebilir veya sadece bir zevk meselesi olabilir.
Ami Tavory

8

İşte bu tartışmaya beş sentim:

struct Foo {
    Foo(int, double) {}
};

struct Bar {
    explicit Bar(int, double) {}
};

void foo(const Foo&) {}
void bar(const Bar&) {}

int main(int argc, char * argv[]) {
    foo({ 42, 42.42 }); // valid
    bar({ 42, 42.42 }); // invalid
    return 0;
}

Kolayca görebileceğiniz gibi, yapıcısı olarak bildirildiği için explicitbaşlatıcı listesinin barişleviyle birlikte kullanılmasını engeller .struct Barexplicit

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.