İşlev argümanı olarak {} neden belirsizliğe yol açmıyor?


20

Bu kodu düşünün:

#include <vector>
#include <iostream>

enum class A
{
  X, Y
};

struct Test
{
  Test(const std::vector<double>&, const std::vector<int>& = {}, A = A::X)
  { std::cout << "vector overload" << std::endl; }

  Test(const std::vector<double>&, int, A = A::X)
  { std::cout << "int overload" << std::endl; }
};

int main()
{
  std::vector<double> v;
  Test t1(v);
  Test t2(v, {}, A::X);
}

https://godbolt.org/z/Gc_w8i

Bu yazdırır:

vector overload
int overload

Belirsiz aşırı yük çözünürlüğü nedeniyle neden bir derleme hatası oluşturmuyor? İkinci kurucu kaldırılırsa, vector overloadiki kez elde ederiz . Metrik nedir tarafından nasıl / intBir açık bir şekilde iyiye maç {}daha std::vector<int>?

Yapıcı imzası kesinlikle daha da kesilebilir, ama sadece eşdeğer bir kod parçası tarafından kandırıldım ve bu soru için önemli bir şeyin kaybolmadığından emin olmak istiyorum.


Eğer doğru hatırlıyorsam {} bir kod bloğu olarak değişkenlere 0 atar - örnek: const char x = {}; int vb. için 0 (boş karakter) olarak ayarlanır.
— Seti

2
@Seti {}Bazı özel durumlarda etkili olan budur , ancak genellikle doğru değildir (yeni başlayanlar, std::vector<int> x = {};işler, std::vector <int> x = 0;yapmaz). " {}Sıfır atar " kadar basit değil .
— Max Langhof

Doğru, o kadar basit değil, ama yine de sıfır atar - bu beaviour'un oldukça kafa karıştırıcı olduğunu ve gerçekten kullanılmaması gerektiğini düşündüm
— Seti

2
@Seti struct A { int x = 5; }; A a = {};hiçbir anlamda sıfır atamaz , bir Aile oluşturur a.x = 5. Bu farklıdır A a = { 0 };, a.xsıfır olarak başlar. Sıfırın doğasında olmayan {}, her türün varsayılan olarak nasıl yapılandırıldığı veya değerle başlatıldığının doğasında vardır. Bkz burada , burada ve burada .
— Max Langhof

Hala varsayılan değerlerin kafa karıştırıcı olduğunu düşünüyorum (her zaman davranışı kontrol etmenizi ya da her zaman çok fazla bilgi sahibi olmanızı gerektirir)
— Seti

Yanıtlar:


12

Bu öyle [over.ics.list] , vurgu mayın

6 Aksi takdirde, parametre toplu olmayan bir X sınıfı ise ve [over.match.list] başına aşırı yük çözünürlüğü, X türünde bir nesnenin argüman başlatıcı listesinden başlatılmasını gerçekleştirmek için X'in en iyi tek bir yapıcısını C seçer:

  • C bir başlatıcı listesi yapıcısı değilse ve başlatıcı listesi cv U türünde tek bir öğeye sahipse (burada U X veya X'den türetilmiş bir sınıfsa), örtük dönüşüm sırasında U X ise Tam Eşleme sırası veya U, X'den türetilir.

  • Aksi takdirde, örtük dönüşüm dizisi, ikinci standart dönüşüm dizisi bir kimlik dönüşümüne sahip olan kullanıcı tanımlı bir dönüşüm dizisidir.

9 Aksi takdirde, parametre tipi bir sınıf değilse:

  • [...]

  • başlatıcı listesinde öğe yoksa, örtük dönüşüm sırası kimlik dönüşümüdür. [ Misal:

    void f(int);
    f( { } ); // OK: identity conversion

    son örnek]

std::vectorYapıcı ve kalın gördüğü bir kullanıcı tanımlı konversiyon bir mermi ile başlatılır. Bu arada, bir için int, bu kimlik dönüşümüdür, bu yüzden ilk müşterinin rütbesini düşürür.


Evet, doğru görünüyor.
— Columbo

Bu durumun standartta açıkça dikkate alındığını görmek ilginçtir. Gerçekten belirsiz olmasını beklerdim (ve bu şekilde kolayca belirtilmiş olabilir gibi görünüyor). Son cümlenizde akıl yürütme takip edemiyorum - 0türü var intama türü değil std::vector<int>, bu nasıl "türsüz" doğası için bir "sanki" wrt {}?
— Max Langhof

@MaxLanghof - Buna bakmanın diğer yolu, sınıf dışı türler için, herhangi bir streçle kullanıcı tanımlı bir dönüşüm olmamasıdır. Bunun yerine, varsayılan değer için doğrudan bir başlatıcıdır. Dolayısıyla bu durumda bir kimlik.
— StoryTeller - Unlander Monica

Bu kısım açık. Kullanıcı tanımlı bir dönüşüm ihtiyacından şaşırdım std::vector<int>. Söylediğiniz gibi, "parametre türü argümanın türüne karar verir" bekler ve bir {}"tür" (tabiri caizse) std::vector<int>başlatmak için (kimlik olmayan) dönüşüm gerekmez std::vector<int>. Standart açıkça söylüyor, bu yüzden, ama benim için bir anlam ifade etmiyor. (Dikkat edin, sizin veya standardın yanlış olduğunu iddia etmiyorum, sadece zihinsel modellerimle uzlaştırmaya çalışıyorum.)
— Max Langhof

Tamam, bu düzenleme umduğum çözüm değildi, ama yeterince adil. : D Zaman ayırdığınız için teşekkürler!
— Max Langhof
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.