T'nin std :: declval <T> `de kullanılacak tam bir tür olması gerekir mi?


11

Bu örneği düşünün ( buradan geliyor ):

#include <type_traits>
#include <iostream>
template <typename U>
struct A {
};

struct B {
   template <typename F = int>
   A<F> f() { return A<F>{}; }

   using default_return_type = decltype(std::declval<B>().f());
};

int main()
{
    B::default_return_type x{};
    std::cout << std::is_same< B::default_return_type, A<int>>::value;
}

Bu gcc9.2 üzerinde hatasız derler şikayet 10.0.0 ama gcc7.2 ve clang Btam olmayan. Clangs hatası:

prog.cc:11:58: error: member access into incomplete type 'B'
   using default_return_type = decltype(std::declval<B>().f());
                                                         ^
prog.cc:7:8: note: definition of 'B' is not complete until the closing '}'
struct B {
       ^
prog.cc:16:8: error: no type named 'default_return_type' in 'B'
    B::default_return_type x{};
    ~~~^
prog.cc:17:35: error: no member named 'default_return_type' in 'B'
    std::cout << std::is_same< B::default_return_type, A<int>>::value;
                               ~~~^

1
Soru başlığı hatayla eşleşmiyor mu? Bana göre, GCC şikayet ediyor gibi görünüyor .f(). Mantıklı; eksik türün Bbir üyesi yoktur f.
MSalters

@MSalters Ben de aynı şeyi düşündüm, ama sonra burada gerçek sorun nedir? Bir örnek aldığınızda std::declvalartık türün eksiksiz olup olmadığı artık önemli değil (ve bununla ilgili yanlış olduğumu tahmin ediyorum)
idclev 463035818 10:19

[expr.ref] / 2 (C ++ 11) sınıf üyesi erişimi hakkında şunları söylüyor: "İlk seçenek (nokta) için ilk ifade tam sınıf türüne sahip olmalıdır" . Ve Bne tam ne de tam olarak kabul olduğunu alias-declaration.
Dil Avukatı


1
@LanguageLawyer tamam o zaman benim yorum kapalı olduğunu kabul ediyorum ve c ++ 11 bir şey değişti gibi görünüyor, yeni standartlarda yukarıdaki ok yapar ama c ++ 11 değil. Bir cevap yazabilir misiniz?
idclev 463035818

Yanıtlar:


9

Hatanın kaynağı değil std::declval , sınıf üyesi erişimi eksik.

CWG1836'nın çözünürlüğü 2,5 yıl önce birleştirilene kadar, standart sınıfın bir sınıf üyesi erişim ifadesinde ( E1.E2) tamamlanmasını gerektiriyordu.
[expr.ref] / C ++ 11 içinde 2 :

İlk seçenek (nokta) için, ilk ifade tam sınıf tipine sahip olacaktır.

[expr.ref] / 2, C ++ 17'de :

İlk seçenek (nokta) için ilk ifade, tam sınıf tipine sahip bir glvalue olacaktır.

Ve bir sınıf alias-declarationkendi içinde tamamlanmış sayılmaz member-specification.
[class.mem] / 6 C ++ 17'de :

A sınıfı tamamen tanımlanmış nesne türü ([basic.types]) (ya da tam tipi) kapanış olarak kabul edilir }bir sınıf belirleyici . Sınıf üyesi belirtimi içinde sınıf, işlev gövdeleri, varsayılan bağımsız değişkenler, istisna belirtici olmayanlar ve varsayılan üye başlatıcıları (iç içe sınıflardaki bu tür şeyler dahil) içinde tam olarak kabul edilir . Aksi takdirde, kendi sınıf üyesi spesifikasyonu içinde eksik kabul edilir .


8

Gönderen [declval] :

Notlar: şablon parametresi Tarasında declvaltamamlanmamış türü olabilir.

Bu ifade C ++ 11'den beri var (bu yüzden derleyicilerin daha önceki bir standarda uyması mümkün değil)


harika, ben ne umuyordum. Gcc sabit gibi görünüyor, henüz değil clang
idclev 463035818

@ formerlyknownas_463035818: İlk düşüncem Tbunun tam bir tür olması gerektiğiydi. Standart kontrol sevindim.
AndyG
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.