2012-02-14 21 views
8

Gcc 4.6 kullanıyorum. Değişken bir fonksiyona geçmek zorunda olduğum bir vektör v vektörünün olduğunu varsayalım (const char * format, ...).Geçiş std :: vector <int> öğeleri variadic işlevi

Bunu yapmanın bir yaklaşımdır.

 void VectorToVarArgs(vector<int> &v) 
     { 
      switch(v.size()) 
      { 
       case 1: f("%i",    v[0]); 
       case 2: f("%i %i",   v[0], v[1]); 
       case 3: f("%i %i %i",  v[0], v[1], v[2]); 
       case 4: f("%i %i %i %i", v[0], v[1], v[2], v[3]); 

       // etc... 
       default: 
        break; 
      } 
     } 

     // where function f is 
     void f(const char* format, ...) 
     { 
      va_list args; 
      va_start (args, format); 
      vprintf (format, args); 
      va_end (args); 
     } 

sorun vektör v öğelerin rastgele sayıda desteklemediği elbette Ancak, ben de işleri va_lists nasıl anlamış inandığımız ilke, , yani "...", 'dan önceki son argüman adresinden başlayarak yığındaki argümanları okuyarak Şimdi vektör öğesi değerlerini bir bellek bloğuna kopyalamanın mümkün olacağını düşündüm (örn. myMemBlock ve adres 'format' sonra ikinci argüman olarak iletir. Açıkçası bu, myMemBlock'un f(), yani bir yığın gibi beklendiği gibi yapılandırılmasını gerektirir.

  1. Böyle bir şey yapılabilir mi?
  2. Alternatif olarak, vektör öğesi değerlerini gerçek yığın üzerinde bazı satır içi sihirbaz sihirbazı, çağrı işlevi f() ile itip mümkün olur mu?

Son olarak, işler Ben umurumda değil:

  1. kod taşınabilir değildir olabilir. Tamam sadece gcc ile ilgileniyorum.
  2. Önişlemci korsanlığı ile ilgili başka yaklaşımlar olabilir.
  3. printf() gibi biçimlendirme için varadik işlevlerin kullanımı C++ için önerilmez.
  4. Değişken şablon işlevlerinin kullanımı.
+1

Bildiğim kadarıyla kendi va_arg listenizi "oluşturmak" mümkün değildir. Yapabilecekleriniz, doğrudan f() işlevinizi aşırı yükleyerek vektörü geçirmektir. – Gui13

+0

Va_arg'ı yeniden oluşturmak istemiyorum, sadece çalışmam için va_arg için bir yığın taklit etmek istiyorum. – user1142580

cevap

2

Tamam, işte kısmi bir çözüm! o gerçekten variadic fonksiyonları, ama argüman olarak diyebileceğiniz bir va_list'i kabul olanlar için geçerli değildir çünkü, Kısmi. Ama bence tam çözüm çok uzak değil.

Bu örneklere dayanmaktadır burada bulduğu:

  1. Dinamik diyebileceğiniz bir va_list'i

  2. Forge https://bbs.archlinux.org/viewtopic.php?pid=238721 oluşturmak va_list http://confuseddevelopment.blogspot.com/2006/04/dynamically-creating-valist-in-c.html

Bu kod linux ve VC++ 2008 başarıyla diğer platformlarda da desteklenebilir üzerinde gcc ile test, ama bu size kalmış edilir.

benim için önemli anlayış ise va_list temelde dinamik verilerle doldurulabilir ve vprintf, vfprintf, argüman olarak kabul vsprintf gibi işlevlere geçirilebilir bir dolu dizide, başka bir şey değildir olmasıydı.

Vektör öğeleri bu işlevlerden birine aktarmak, vektör öğeleri için yeterli bellek ayırarak çalışabilir ve bunları aramadan önce kopyalayabilir.

#include <iostream> 
#include <stdio.h> 
#include <stdarg.h> 
#include <string> 
#include <vector> 
#include <alloca.h> 

using namespace std; 


class Format 
{ 
    typedef vector<unsigned long> ULVector; 
    ULVector _args; 
    string _format; 

    public: 
     Format(const char* format) : _format(format) 
     {} 

     Format &operator<<(int arg) { 
      _args.push_back((unsigned long)arg); 
      return *this; 
     } 

     Format &operator<<(const char* arg) { 
      _args.push_back((unsigned long)arg); 
      return *this; 
     } 

     string format() { 
      union { 
       va_list varargs; 
       unsigned long* packedArray; 
      } fake_va_list; 

      // malloc would do it as well! 
      // but alloca frees the mem after leaving this method 
      unsigned long *p = (unsigned long*)alloca(_args.size() * sizeof(unsigned long)); 
      fake_va_list.packedArray = p; 

      ULVector::iterator i = _args.begin(); 
      for (int n=0; i != _args.end(); i++, n++) { 
       p[n] = *i; 
      } 

      char buffer[512]; 
      const char* fmt = _format.c_str(); 
      vsprintf(buffer, fmt, fake_va_list.varargs); 

      // place a free(p) here if you used malloc 
      return string(buffer); 
     } 
}; 


ostream& operator <<=(ostream &os, Format &obj) { 
     os << obj.format(); 
     return os; 
} 


int main() 
{ 
    // we use '<<=' operator here which has lower precedence than '<<' 
    // otherwise we have to write 
    // cout << (Format("\n%x %s %x %c\n") << etc.); 
    cout <<= Format("\n%x %s %x %c\n") << 0x11223344 << "VectorToVarArg" << 0xAABBCCDD << '!'; 
    return 0; 
} 

ne yaptığını Tahmin:

, burada dinamik tahsis yığın yaklaşım olduğunu söyledikten? Bir vektörde toplanan parametrelerle printf (..) stil formatlama sağlar. Evet, mükemmel değil ama istediğimi yapıyor. va_pass http://www.codeproject.com/Articles/9968/va_list-va_start-va_pass-or-how-to-pass-variable-a

+0

Tamam, tam cevap burada sunulan yaklaşım kullanılarak sağlanabilir: http://www.codeproject.com/Articles/9968/va_list-va_start-va_pass-or-how-to-pass-variable-a Ancak Farklı bir lisans için kodu buraya kopyalayamıyorum. – user1142580

0

Vektörün her öğesini yazdırmak için STL algoritması for_each özelliğini kullanabilirsiniz.

3

http://cocoawithlove.com/2009/05/variable-argument-lists-in-cocoa.html adresinde "Sahte va_list oluşturuluyor" bölümü var. Kakao için, ama GCC için internette bir şeyler bulabilirsin. Ben kesinlikle hiçbir ipucu var,

#include <string> 
#include <cstdio> 
#include <vector> 
#include <cstdarg> 
using namespace std; 

struct my_list { 
    unsigned int gp_offset; 
    unsigned int fp_offset; 
    void *overflow_arg_area; 
    void *reg_save_area; 
}; 

void f(const char* format, ...) { 
    va_list args; 
    va_start (args, format); 
    vprintf (format, args); 
    va_end (args); 
} 

void test(const vector<int>& v) { 
    string fs; 
    for (auto i = v.cbegin(); i !=v.cend(); ++i) { 
     if (i != v.cbegin()) { 
      fs += ' '; 
     } 
     fs += "%i"; 
    } 
    my_list x[1]; 
    // initialize the element in the list in the proper way 
    // (however you do that for GCC) 
    // where you add the contents of each element in the vector 
    // to the list's memory 
    f(fs.c_str(), x); 
    // Clean up my_list 
} 

int main() { 
    const vector<int> x({1, 2, 3, 4, 5}); 
    test(x); 
} 

Ama:

Sonra ben böyle bir şey yapacağını tahmin değilim. :)

+0

Bu çok ilginç görünüyor! Şimdilik teşekkürler! Sonuçları bildireceğim. – user1142580

+1

Yardımınız için teşekkürler! – user1142580

2

Yansımanız doğru seviyede değil.

Vektörü değişken argüman listelerine dönüştürmek istediğinizi söylediğinizde, değişken argüman listesini alan işlevin ilginizi çekeceği bir şey vardır.

Gerçek soru şu ki, f'dan aynı şeyi nasıl yapabilirim, ama vector'dan başlayarak?

f numaralı aramayı iletmek, çözümü başlatabilir ancak sonuç ortada olmayabilir.f faiz artık gerçekten belirgin değildir işaret

#include <boost/algorithm/string/join.hpp> 

void f(std::vector<int> const& vi) { 
    std::cout << boost::join(vi, " "); 
} 

At which: dışarıda kütüphanelerine erişimi varsa,

void f(std::vector<int> const& vi) { 
    bool first = true; 
    for (int i: vi) { 
    if (first) { first = false; } else { std::cout << ' '; } 
    std::cout << i; 
    } 
} 

Veya: bu sadece baskı ilgiliyse

.

+0

Diyelim ki bu sadece baskı ile ilgili. Sadelik uğruna v vektör olarak tanımladı. Ancak bu sadece kendim için bir başlangıç ​​noktası olmalıydı. V farklı POD tipleri içerecek şekilde değiştirilecekse, vprintf() biçimlendirmesini kullanmak isterim. – user1142580

1

Eğer boost format yararlanabilecek gibi verilen kendi cevap bakılırsa, bu sesler: Bu makalede de göz, Ek

D

: Ayrıca, iki büyük platformlar kapsar.

Örnekler: Tabii

#include <iostream> 
#include <string> 
#include <sstream> 
#include <boost/format.hpp> 
using namespace std; 
using namespace boost; 

template <typename T> 
string formatted_str_from_vec(const T& v) { 
    ostringstream fs; 
    size_t count = 1; 
    for (const auto& i : v) { 
     if (&i != &v[0]) { 
      fs << " "; 
     } 
     fs << '%' << count << '%'; 
     ++count; 
    } 
    format fmtr(fs.str()); 
    for (const auto& i : v) { 
     fmtr % i; 
    } 
    // looks like fmtr("%1% %2% %3% %4%") % v[0] % v[1] etc. 
    return fmtr.str(); 
} 

int main() { 
    cout << formatted_str_from_vec(vector<int>({1, 2, 3, 4, 5, 6, 7, 8, 8, 10, 11, 12})) << endl; 
    cout << formatted_str_from_vec(vector<string>({"a", "b", "c"})) << endl; 
    format test1("%1% %2% %3%"); 
    test1 % 1 % "2" % '3'; 
    cout << test1.str() << endl; 
    format test2("%i %s %c"); 
    test2 % 1 % "2" % '3'; 
    cout << test2.str() << endl; 
    format test3("%1% %2%"); 
    test3.exceptions(io::no_error_bits); 
    test3 % 'g'; 
    cout << test3.str() << endl; 
    format test4("%%1%% = %1%"); 
    test4 % "zipzambam"; 
    cout << test4.str() << endl; 
} 

// g++ -Wall -Wextra printvector.cc -o printvector -O3 -s -std=c++0x 

, bunların hiçbiri sadece bir vektör yazdırmak için gereklidir.

+0

Bunun kısmi bir çözüm olduğunu belirttim. Sorduğum soruya hitap eden eksiksiz çözüm, kendi cevabım altında yorumladığım va_pass kullanılarak sağlanabilir. Öneriniz birçok durumda yardımcı olabilir (diğer bir deyişle destekleme mevcut veya takdir edilmişse), dolayısıyla "oylama". – user1142580

İlgili konular