İş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.