SORU
27 AĞUSTOS 2010, Cuma


İleri kullanmanın avantajları

Mükemmel iletme isimsiz rvalue başvuruları rvalue başvuruları t1 t2 adlı dönüştürmek için kullanılır. Bunu yapmanın amacı nedir? Nasıl 17 * & * 18 ** çıkarsak arayan fonksiyonlarını etkiler inner lvalues olarak?

template <typename T1, typename T2>
void outer(T1&& t1, T2&& t2) 
{
    inner(std::forward<T1>(t1), std::forward<T2>(t2));
}

CEVAP
27 AĞUSTOS 2010, Cuma


Yönlendirme sorunu anlamak gerekir. O zaman özetleyeyim 57**.

Temelde, ifade vermiş E(a, b, ... , c) ifade f(a, b, ... , c) eşdeğer olmasını istiyoruz. C 03, bu imkansız. Birçok girişim vardır, ama hepsi bazı konuda başarısız.


En basit lvalue-bir referans kullanmak için:

template <typename A, typename B, typename C>
void f(A& a, B& b, C& c)
{
    E(a, b, c);
}

Ama bu geçici değerleri işlemek için başarısız: bu olamaz lvalue başvuru. bir bağlı olarak f(1, 2, 3);,

Bir sonraki girişimi olabilir:

template <typename A, typename B, typename C>
void f(const A& a, const B& b, const C& c)
{
    E(a, b, c);
}

Yukarıdaki sorunu giderir, ama flop çevirir. Şimdi E olmayan sabit tartışmaya izin vermek için başarısız:

int i = 1, j = 2, k = 3;
void E(int&, int&, int&); f(i, j, k); // oops! E cannot modify these

Üçüncü girişimi inş-başvuruları kabul eder, ama o const_cast28**:

template <typename A, typename B, typename C>
void f(const A& a, const B& b, const C& c)
{
    E(const_cast<A&>(a), const_cast<B&>(b), const_cast<C&>(c));
}

Bu değerleri kabul eden, tüm değerleri geçebilir, ama potansiyel olarak tanımlanmamış davranışa yol açar:

const int i = 1, j = 2, k = 3;
E(int&, int&, int&); f(i, j, k); // ouch! E can modify a const object!

Nihai çözüm doğru her şey...imkansız sürdürmek pahasına işler. f ile aşırı yükleme sağlartümsabit kombinasyonları ve non-sabit:

template <typename A, typename B, typename C>
void f(A& a, B& b, C& c);

template <typename A, typename B, typename C>
void f(const A& a, B& b, C& c);

template <typename A, typename B, typename C>
void f(A& a, const B& b, C& c);

template <typename A, typename B, typename C>
void f(A& a, B& b, const C& c);

template <typename A, typename B, typename C>
void f(const A& a, const B& b, C& c);

template <typename A, typename B, typename C>
void f(const A& a, B& b, const C& c);

template <typename A, typename B, typename C>
void f(A& a, const B& b, const C& c);

template <typename A, typename B, typename C>
void f(const A& a, const B& b, const C& c);

N bağımsız 2 gerektirirNkombinasyon, bir kabus. Bu otomatik olarak yapmak istiyoruz.

(Bu 11. C bizim için yapmak) için derleyici için bize ne kadar etkili olduğunu


C 11, biz bunu düzeltmek için bir şans. Başka bir yol bulmak zorunda kaldık One solution modifies template deduction rules on existing types, but this potentially breaks a great deal of code..

Çözüm yerine yeni eklenen kullanmaktırrvalue-kaynaklar;- başvuru rvalue türleri deducing zaman yeni kurallar getirecek ve istenen sonucu oluşturmak. Tüm bunlardan sonra, muhtemelen kod Ara veremeyiz.

Eğer bir referans (Dipnot referans kapsayan bir terim T& T&& her iki anlamı) başvuru verilirse, sonuç türü anlamak için aşağıdaki kuralı kullanın:

"[verilen] bir tür TR bir başvuru için bir tür T, bir girişim oluşturmak için type “lvalue başvuru için cv TR” oluşturur tipi “lvalue başvuru T”, bir girişim oluşturmak için type “rvalue başvuru için cv TR” oluşturur tipi TR."

Veya tablo biçiminde:

TR   R

T&   &  -> T&  // lvalue reference to cv TR -> lvalue reference to T
T&   && -> T&  // rvalue reference to cv TR -> TR (lvalue reference to T)
T&&  &  -> T&  // lvalue reference to cv TR -> lvalue reference to T
T&&  && -> T&& // rvalue reference to cv TR -> TR (rvalue reference to T)

Eğer bir argüman lvalue Bir, Aksi takdirde, normalde biz anlamak için A. lvalue başvurusu ile şablon tartışma tedarik ediyoruz. daha sonra, bağımsız değişken kesinti şablon ile: Bu sözde verirevrensel referanslar(forwarding reference şimdi resmi bir terim).

Bu neden kullanışlıdır? Çünkü birleşik bir değer türü kategorisi izlemek için yeteneği korumak: eğer bir lvalue olsaydı, lvalue başvuru bir parametre var, aksi takdirde rvalue başvuru bir parametre var.

Kod:

template <typename T>
void deduce(T&& x); 

int i;
deduce(i); // deduce<int&>(int& &&) -> deduce<int&>(int&)
deduce(1); // deduce<int>(int&&)

Son şey "değişken." değeri kategorinin ileri. Unutmayın, bu fonksiyon içinde parametre bir şey için bir lvalue olarak geçmiş olabilir:

void foo(int&);

template <typename T>
void deduce(T&& x)
{
    foo(x); // fine, foo can refer to x
}

deduce(1); // okay, foo operates on x which has a value of 1

Bu hiç iyi değil. E aldığımız değer kategorisi aynı tür almak gerekiyor! Çözüm şu:

static_cast<T&&>(x);

Bu ne işe yarıyor? deduce işlev içinde olduğumuzu düşünün, ve bir lvalue geçmiş olduk. Bu T statik dökme için ** 42 A& sadece A&, ve bu yüzden hedef bir tür olduğu anlamına gelir. x A& bir yana biz hiçbir şey yapmak ve lvalue başvurusu ile bırakılır.

Geçmiş olduğumuz bir rvalue, T statik oyuncular için hedef türü A&& A. Cast rvalue bir ifade, sonuçlarıartık lvalue başvuru geçebilir. Parametre değeri kategori koruduk.

Birlikte bu koyarak bize verir "mükemmel iletme":

template <typename A>
void f(A&& a)
{
    E(static_cast<A&&>(a)); 
}

f bir lvalue, E aldığında bir lvalue alır. f bir rvalue, E aldığında bir rvalue alır. Mükemmel.


Ve tabii ki, çirkin kurtulmak istiyoruz. static_cast<T&&> ve unutma şifreli garip; hadi yerine fayda fonksiyonu aynı şeyi yapar forward olarak adlandırılan:

std::forward<A>(a);
// is the same as
static_cast<A&&>(a);

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Doc Adams

    Doc Adams

    20 HAZİRAN 2007
  • RiceBunny

    RiceBunny

    16 ŞUBAT 2006
  • TV and Lust

    TV and Lust

    26 HAZİRAN 2006