2010-04-19 12 views
23

Bu büyük olasılıkla gerçekten basit bir açıklama olacak, ancak hatalı olduğumda olabildiğince fazla destek vereceğim. Gelişmiş olmak için çok özür dilerim. Ben gcc4.5 kullanıyorum ve ben C++ 0x desteği hala biraz deneysel olduğunu fark ediyorum, ama gördüğüm davranış için hata ile ilgili olmayan bir nedeni olduğu varsayımı üzerine hareket edeceğim.Variadic işlevler için bir dönüş tipi yinelemeli olarak oluştururken garip davranış

Değişken işlev şablonları ile denemeler yapıyorum. Son hedef, std::pair'dan bir liste oluşturmaktı. Özel bir tip değil, sadece bir çift nesne dizisi olması gerekiyordu. Listeyi oluşturan işlev, bir şekilde özyinelemeli olmalıydı; nihai geri dönüş değeri, özyinelemeli çağrıların sonucuna bağlıdır. Ek bir büküm olarak, listeye eklenmeden önce birbirini izleyen parametreler bir araya getirilir. Yani [1, 2, 3, 4, 5, 6] 'yı geçersem sonuç {1 + 2, {3 + 4, 5 + 6}} olmalıdır.

İlk denemem oldukça saftı. İki aşırı yüklenme olan bir fonksiyon. Biri iki özdeş parametre aldı ve basitçe toplamlarını verdi. Diğer iki parametre ve bir parametre paketi aldı. Dönüş değeri, iki ayarlanmış parametrenin toplamı ve tekrar eden çağrıdan oluşan bir çiftti. Geriye doğru bakıldığında, bu açıkça hatalı bir stratejiydi, çünkü geri dönüş türünü anlamaya çalıştığımda işlev bildirilmiyor, bu nedenle, yinelemeli olmayan sürümü çözmek için bir seçeneği yok. Anladığım kadarıyla. Kafamın karıştığı yer ikinci iterasyondu. Bu fonksiyonları bir şablon sınıfının statik üyeleri yapmaya karar verdim. Fonksiyon çağrıları kendilerini parametrelendirmez, bunun yerine tüm sınıflar. Benim varsayımım, özyinelemeli işlev, dönüş türünü oluşturmaya çalıştığı zaman, yapının yepyeni bir versiyonunu kendi statik işleviyle başlatacaktı ve her şey kendi kendine çalışacaktı.

sonucuydu:

kusurlu kodu: "hata BuildStruct<double, double, char, char>::Go(const char&, const char&) yapılan çağrı için eşleşen fonksiyonu":

static auto Go(const Type& t0, const Type& t1, const Types&... rest) 
    -> std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))> 

Benim karışıklık BuildStruct için parametreler her zaman aynı olmalıdır olmasından kaynaklanır argümanlar BuildStruct::Go'a gönderilir, ancak hata kodunda Go, ilk iki çift parametresi eksiktir. Burada neyi özlüyorum? Eğer statik fonksiyonların nasıl seçileceğine dair ilk varsayım yanlış olsaydı, neden bir işlev bulamıyorsa, neden yanlış fonksiyon çağırmaya çalışıyor? Sadece willy-nilly türlerini karıştırıyor gibi görünüyor ve ben sadece neden diye bir açıklama ile gelemiyorum. İlk aramaya ek parametreler eklediğimde, başarısız olmasından önce her zaman bu son adıma iner, dolayısıyla muhtemelen özyinenin kendisi en azından kısmen çalışır durumdadır. Bu, hemen her zaman bir işlev çağrısını bulamayan ilk denemenin aksine. Sonuçta, ilk iki denemeden neredeyse hiç benzemeyen oldukça zarif bir çözümle sorunu çözdüm. Yani yapmak istediğimi nasıl yapacağımı biliyorum. Gördüğüm başarısızlık için bir açıklama arıyorum.

Sözlü açıklamanın yeterli olmadığından emin olmak için tam kod takip ediyorum. İlk önce bazı ortak metinler, eğer kodu çalıştırmaya ve kendiniz için görmeye zorlanıyorsanız. Daha sonra makul bir şekilde başarısız olan ilk denemeden sonra, ikinci denemeye gitmedi.

#include <iostream> 
using std::cout; 
using std::endl; 

#include <utility> 

template<typename T1, typename T2> 
std::ostream& operator <<(std::ostream& str, const std::pair<T1, T2>& p) { 
    return str << "[" << p.first << ", " << p.second << "]"; 
} 

//Insert code here  

int main() { 
    Execute(5, 6, 4.3, 2.2, 'c', 'd'); 
    Execute(5, 6, 4.3, 2.2); 
    Execute(5, 6); 

    return 0; 
} 

Sigara yapı çözümü:

template<typename Type> 
Type BuildFunction(const Type& t0, const Type& t1) { 
    return t0 + t1; 
} 

template<typename Type, typename... Rest> 
auto BuildFunction(const Type& t0, const Type& t1, const Rest&... rest) 
     -> std::pair<Type, decltype(BuildFunction(rest...))> { 
    return std::pair<Type, decltype(BuildFunction(rest...))> 
        (t0 + t1, BuildFunction(rest...)); 
} 

template<typename... Types> 
void Execute(const Types&... t) { 
    cout << BuildFunction(t...) << endl; 
} 

Ortaya hataları:

test.cpp: In function 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]': 
test.cpp:33:35: instantiated from here 
test.cpp:28:3: error: no matching function for call to 'BuildFunction(const int&, const int&, const double&, const double&, const char&, const char&)' 

Struct çözeltisi:

template<typename... Types> 
struct BuildStruct; 

template<typename Type> 
struct BuildStruct<Type, Type> { 
    static Type Go(const Type& t0, const Type& t1) { return t0 + t1; } 
}; 

template<typename Type, typename... Types> 
struct BuildStruct<Type, Type, Types...> { 
    static auto Go(const Type& t0, const Type& t1, const Types&... rest) 
     -> std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))> { 
    return std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))> 
       (t0 + t1, BuildStruct<Types...>::Go(rest...)); 
    } 
}; 

template<typename... Types> 
void Execute(const Types&... t) { 
    cout << BuildStruct<Types...>::Go(t...) << endl; 
} 

Ortaya hataları:

test.cpp: In instantiation of 'BuildStruct<int, int, double, double, char, char>': 
test.cpp:33:3: instantiated from 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]' 
test.cpp:38:41: instantiated from here 
test.cpp:24:15: error: no matching function for call to 'BuildStruct<double, double, char, char>::Go(const char&, const char&)' 
test.cpp:24:15: note: candidate is: static std::pair<Type, decltype (BuildStruct<Types ...>::Go(BuildStruct<Type, Type, Types ...>::Go::rest ...))> BuildStruct<Type, Type, Types ...>::Go(const Type&, const Type&, const Types& ...) [with Type = double, Types = {char, char}, decltype (BuildStruct<Types ...>::Go(BuildStruct<Type, Type, Types ...>::Go::rest ...)) = char] 
test.cpp: In function 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]': 
test.cpp:38:41: instantiated from here 
test.cpp:33:3: error: 'Go' is not a member of 'BuildStruct<int, int, double, double, char, char>' 
+0

Şu an bunu denemiyorum, ancak ertelenmiş iade türü kesintisi hala başarısız olabilir. İkinci durumda dönüş türünü yazabilmeniz gerekir: 'typedef std :: pair :: result_type> result_type;' (ve ilk uzmanlık için uygun şekilde) ve bunları kullanın: 'static result_type Go (...); ' – visitor

+0

Sanırım bunu denedim ama sonucu hatırlamıyorum. Eve geldiğimde başka bir çekim yapacağım. Teşekkürler. –

+31

İyi efendim, bu * okumak için çok fazla * –

cevap

2

Yorumların okunması, bunun G + 'nın belirli bir sürümünde çok lokalize bir hata olduğunu açıkça görüyor ve buradaki tüm cevaplar var.

+0

Bir ay önce bu sonuca vardım, cevap verdiğiniz için teşekkürler, böylece gitmemizi sağlayın :) –