std :: çift <otomatik, otomatik> dönüş türü


16

Ben oynamalar autoiçinde std::pair. Aşağıdaki kodda, fonksiyonun bir template parametresine bağlı olan bir tür fdöndürmesi beklenir std::pair.

Çalışan bir örnek:

ÖRNEK 1

template <unsigned S>
auto f()
{
    if constexpr (S == 1)
        return std::pair{1, 2}; // pair of ints
    else if constexpr (S == 2)
        return std::pair{1.0, 2.0}; // pair of doubles
    else
        return std::pair{0.0f, 0.0f}; // pair of floats
}

Bu, gcc 9.2, gcc 10.0, clang 9.0 ve clang 10.0 ile çalışır.

Sonra, std::pairnetlik nedenleriyle açıkça bir dönüş türü yazmak istedim :

ÖRNEK 2

template <unsigned S>
std::pair<auto, auto> f()
{
    if constexpr (S == 1)
        return {1, 2};
    /* ... */
}

Hem gcc 9.2 / 10.0 hem de clang 9.0 / 10.0 bunu derleyemedi.

gcc 9.2

error: invalid use of 'auto'
error: template argument 1 is invalid // first argument (auto) of std::pair
error: template argument 2 is invalid // second argument (auto) of std::pair
error: cannot convert '<brace-enclosed initializer list>' to 'int' in return

Son hata mesajından, gcc 9.2 std::pair<auto, auto>bunun bir olduğuna inanıyor gibi görünüyor int. Bu nasıl açıklanabilir?

gcc 10.0

error: returning initializer list

Bu hata anlaşılabilir, ancak std::pairkurucunun çağrılmasını bekledim, yoksa burada eksik olduğum bir şey var mı?

clang 9.0 ve 10.0

'auto' not allowed in template argument
excess elements in scalar initializer
no matching function for call to 'f'

Tamam, clang bunların hiçbirini sevmiyor. İkinci hata mesajından, clang da dönüş türünün olduğuna inanıyor gibi görünüyor int.

Son olarak, gcc 10.0 ile derlenen hatayı düzeltmek için, std::pairaçıkça dönmeye karar verdim :

ÖRNEK 3

template <unsigned S>
std::pair<auto, auto> f()
{
    if constexpr (S == 1)
        return std::pair{1, 2};
    /* ... */
}

clang 9.0 ve 10.0

Öncekiyle aynı, ancak ek olarak:

no viable conversion from returned value of type 'std::pair<int, int>' to function return type 'int'

Burada clang hala geri döndüğümüzü düşünüyor int?

gcc 9.2

Öncekinin aynısı.

gcc 10.0

İşe yarıyor!

Bazı özelliklerin hala uygulanması gerekiyor, ya da yukarıda açıklanan durumlardan birinde, doğru ve diğeri yanlış olan bir derleyici var mı? Bence, örnek 2 işe yaramalı. Yoksa değil mi?

Yanıtlar:


23

Sözdizimi:

std::pair<auto, auto> f() { return std::pair(1, 2); }
~~~~~~~~~~~~~~~~~~~~~

Orijinal Concepts TS'nin bir parçasıydı, ancak C ++ 20'nin bir parçası olan Concepts teklifine dahil edilmedi. Bu nedenle, C ++ 20 içindeki tek yer tutucu tipleri auto(ve bunun gibi varyasyonlar auto**) decltype(auto)ve kısıtlı yer tutuculardır ( Concept autove bunların varyasyonları). Bu tür bir iç içe yerleştirilmiş yer tutucu türü çok yararlı olacaktır, ancak C ++ 20'nin bir parçası değildir, böylece işlev bildirimi yanlış biçimlendirilmiştir.

Şimdi, gcc buna izin veriyor çünkü gcc Concepts TS'yi uyguladı ve sanırım bu özelliği korumaya karar verdiler. clang TS'yi asla uygulamamış, öyle değil.

Her iki durumda da, bu:

std::pair<auto, auto> f() { return {1, 2}; }

Her zaman kötü biçimlendirilmiş olurdu. Sözdizimi anlamı biz dönüş türü anlamak ve sonra eşleşmesi gerekir ki pair<T, U>bazı türleri için Tve U. Temel olarak icat edilen işlevi çağırmaya çalışıyoruz:

template <typename T, typename U>
void __f(std::pair<T, U>);

__f({1, 2}); // this must succeed

Ancak, bir türü {1, 2}türetemezsiniz - hazır bir init listesinin bir türü yoktur. Belki de bu araştırılması gereken bir şeydir (en azından böyle basit bir durumda anlaşılması kolay olduğu için), ancak asla izin verilmemiştir. Yani reddetmek her iki şekilde de doğrudur.

Son olarak:

gcc 9.2 std::pair<auto, auto>bunun bir olduğuna inanıyor gibi görünüyor int. Bu nasıl açıklanabilir?

Herhangi bir nedenle (muhtemelen örtük olan C mirasımız nedeniyle int), gcc bir türü tanımadığında veya anlamadığında, sadece inthata mesajlarında yer tutucu olarak kullanır . Bu çok kafa karıştırıcı, çünkü açıkçası intkaynak kodunu değil gcc ile geldi . Ama bu böyle.


"Hazırlanmış init listesinin bir tür argümanı yok" benim için net değil. std :: çift <int, int> f () {dönüş {1,2}; } çalışır ve {1,2} tür içermez (anladığım gibi std :: pair <int, int> yapıcısını çağırır). Belki <auto, auto> ile derleyici {1, 2} başlatıcı listesinde 1 ve 2 türlerini çıkaramaz?
mfnx

@mfnx Tür bağımsız değişkeni yoktur , yalnızca türü yoktur. hazır başlangıç ​​listeleri yalnızca bilinen bir türün başlatılması gibi belirli durumlarda kullanılabilir. Ancak tümdengelimde kullanılamazlar - çünkü türleri yoktur. auto x = {1, 2};Çalışmalar dışında , ancak tüm türler aynı ise.
Barry

2
Çoğu derleyici, ilk hatada durmak yerine, ek hatalar bildirebilmeleri için ondan kurtarmaya çalışın. Bu genellikle ayrılmaz her şeyin bir olduğunu varsaymak anlamına gelir int. intHata mesajlarında bir yer tutucu değildir ; derleyici gerçekten bunun bir olduğunu düşünüyor int. (Bunu daha açık hale getirmek için, gcc muhtemelen bir noktada "int varsayarak" demeliydi.)
Raymond Chen

2
Uzantı için olası başka bir yolun, geri dönüş türleri için sınıf şablonu bağımsız değişkeninin kesilmesine izin vermek olacağını unutmayın std::pair __f{1,2};.
Davis Herring

2
@DavisHerring Gerçekten std::optional f() { return 4; }çalışmak istemezdim .
Barry
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.