Şablonlarda doğru veri türü nasıl döndürülür?


9
#include <iostream>
using namespace std;

template <class X, class Y>
Y big(X a, Y b)
{
   if (a > b)
      return (a);
   else return (b);
}

int main()
{
   cout << big(32.8, 9);
}

Burada CPP şablonlar kullanıyorum, bu yüzden bigargümanları doubleve inttürü atlayarak fonksiyonu çağırdığımda, hangi dönüş cevabını istiyorum double. Buradaki tür, 32yerine döner 32.8.

İstediğim çıktıyı nasıl alabilirim? Uygun bir dönüş türü bigişlevi nasıl yazılır ?


1
Bir işlev yalnızca bir sabit tür döndürebilir . Hangi zamanda döndürüleceğini çalışma zamanında seçemezsiniz.
Jesper Juhl

1
Nasıl std::maxuygulandığına bakmak isteyebilirsiniz . Bir işlevin dönüş türü C ++ derleme zamanında bilinmelidir. Bu nedenle, bu dönüş türünün parametrelerinizin çalışma zamanı değerine bağlı olmasını sağlayamazsınız. Bu nedenle, bu işlev için her iki parametrenin de aynı türe sahip olması gerekir (yani, X türüne sahip, ancak Y'ye sahip değilsiniz).
Boris Dalstein

Yanıtlar:


12

Bir işlevin derleme zamanında bilinmesi gereken yalnızca bir dönüş türü olabilir. Ancak, std::common_typeher iki parametrenin de ima edilebileceği bir tür döndürmek için kullanabilirsiniz.

Olurdu

#include <type_traits>
template <class X, class Y>
typename std::common_type<X,Y>::type big(X a, Y b)
{
   if (a > b)
      return a;
   else return b;
}

Ve gerçekten doublegeçtiğinde bir geri döndüğünü kontrol etmek için bir intve bir doubleyapabiliriz:

int main() {
    auto x = big(4.2,42);
    std::cout << std::is_same<decltype(x),double>::value;
}

Hangi baskılar

1

Not: std::common_typeüçlü operatörü scences'ın arkasında kullanabilir ve bu nedenle bu çözüm diğer cevaplardan ( auto+ üçlü) çok farklı değildir . Gerçek gücü, std::common_typeherhangi bir sayıda parametreyi kabul etmesidir.


10

Dönüş türü derleme zamanında belirlenmelidir. Sınırlıysanız , koşullu bir işleçle sondaki dönüşü kullanabilirsiniz.

template <typename X, typename Y>
auto big(X&& a, Y&& b) -> decltype(a > b ? a : b) // ---> like this
{
   return  a > b ? a : b;
}

Canlı izleyin


Ancak, ya da daha yüksek autogetiri yeterlidir, çünkü koşullu işleçle birlikte aşağıdaki gibi kullanırsanız derleyici doğru türü çıkarır:

template <typename X, typename Y>
auto big(X a, Y b)
{
   return  a > b ? a : b;
}

Canlı izleyin


En azından C ++ 14'ten itibaren sondaki dönüş türüne gerek yoktur.
sweenish

1
@JeJo Evet, sanırım bu da iyi, ama muhtemelen anlamsız, çünkü her iki argümanı da değiştirmiyorsunuz ve dönüş türü her iki durumda da bir lvalue referansı olacak (potansiyel olarak non-olsa da const).
Ceviz

Artık uygulanmadığım için yorumlarımı kaldırdım, ancak parametreye göre değeri alamayacağınıza dair bir uyarı eklemenizi öneririm.
Ceviz

Birisi kodunuza bakarsa, iletilen parametre birisinin hangi dönüş türünü alacağına karar verecek gibi görünüyor ki durum böyle değil ! A, b'den büyük olsa bile, her zaman bir çift geri alırsınız.
Klaus

4

Dönüş türünüzü Ybir intve ikinci parametreniz olarak geçirirken, bunun Ybir int. Burada sürpriz yok.

#include <iostream>

template <typename X, typename Y>
decltype(auto) big(const X& a, const Y& b)  // return type can just be auto as well 
{
    return a > b ? a : b;
}

int main()
{
    std::cout << big(32.8, 9) << '\n';
    std::cout << big(9, 32.8) << '\n';
    std::cout << big(32.8, 90) << '\n';
    std::cout << big(90, 32.8) << '\n';
}

Bu, dört doğru değerin tümünü ekrana yazdırır.

https://godbolt.org/z/fyGsmo

Dikkat edilmesi gereken önemli bir nokta, bunun sadece birbiriyle karşılaştırılabilecek türler için çalışacağıdır, yani derleyici karşılaştırma için bir türü diğerine dolaylı olarak dönüştürecektir.

ÖNEMLİ : Tanımlanmamış davranışı önlemek için parametrelerin referans olarak alınması gerekir. Bu inatla yapıştığım dönüş türü ile ilgilidir. decltype(auto)türlere başvurular döndürebilir. İşleve yerel bir şey döndürürseniz (bağımsız değişken sayısı), tanımsız davranış elde edersiniz.


@walnut Yanlışlıkla bir referans döndürmek, bu sitenin ortaya çıkardığından çok daha zordur. Ama tanımlanmamış davranış hakkında bilmek güzel. Bu zaten yazacağım kod gibi değil; bu bir sorunun cevabıdır.
Ocak'ta

1
Ah. Önceki yorumunuzu etki ve neden değil, iki ayrı nokta olarak okudum. Uygun düzenlemeyi yapabilirim.
Ocak'ta

Fazladan bir feragatname ekledim.
sweenish

2

Herhalde kesin durumunuz için doğru çözüm bu değildir - diğer cevapların istediğiniz şeye çok daha yakın olması muhtemeldir.

Ancak, eğer gerçekten bu yana (nedense, doğru çözüm için zamanında tamamen farklı türlerini döndürmek gerekir) std::variantbir tür güvenli bir birlik olan a kullanmaktır .

#include <variant>

template <typename X, typename Y>
std::variant<X, Y> max(X a, Y b) {
  if (a > b)
    return std::variant<X, Y>(std::in_place_index_t<0>, a);
  else
    return std::variant<X, Y>(std::in_place_index_t<1>, b);
}

Daha sonra, döndürülen değerle başa çıkmak için büyük olasılıkla std::visitveya benzeri bir şekilde onusun arayanın üzerinde olduğuna dikkat edin .


-2

İnt döndürür, çünkü Y bir int'tir ve 32,8 değerini verir. Büyük 32,82 olarak adlandırdığınızda bir şamandıra, ancak 8 bir int ve işlev dönüş türü Y'dir, bu da int'tir.

Çalışma zamanında hangi büyük getirileri yazacağınızı bilmeniz gerektiğinden bunu gerçekten düzeltemezsiniz, bu nedenle a ve b'yi aşağıdaki gibi yapın:

    #include <iostream>
    using namespace std;

    template <typename X>

    X big (X a, X b)
    {
    if (a>b)
    return a;

    else return b;
    }

    int main()
    {
    cout<< big (32.8, 9.0);
    }
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.