2016-04-22 33 views
7

İki boyutlu dizilerle çalışırken, örn. Elemanları sıklıkla ziyaret etmeniz gereken matrisler. Bunu yapmanın düz yol iç içe geçmiş iki döngüler gereğidir:Matrisler üzerinde döngü yapmak için DRY ilkesi nasıl uygulanır?

for(int i=0; i < n; ++i) { 
    for(int j=0; j < m; ++j) { 
    // do something with data[i][j] 
    } 
} 

Bu kod prensibi sonra sık sık kod boyunca tekrar tekrar kopyalanabilir ve kapanır. Bunu DRY olmak için nasıl çözersiniz? Bunu çözmenin tek yolu, fonksiyon işaretçisi olan bir ziyaretçi fonksiyonunu kullanmak, doğru mu?

Düzenleme: Daha yapıcı olmak için, typedef double** Matrix; matris türüne sahip olduğunuzu varsayalım. C için

++ bu bu şekilde çözülebilir olabilir: Loop over matrix elements applying variable function

+0

Bu döngüler oluşturacak bir makro oluşturabilirsiniz. – Crozin

+0

Evet, bu durumda işlev veya makroyu kullanabilirsiniz. –

+0

Bir makro büyük olasılıkla (okuyucuya açık olmayan) dağınık ya da gizli olan 'i' ve 'j' vars (okuyucuya açık olmayan) olarak adlandırılan hayalet yaratacaktır. iç içe olamazdı. – DaveRandom

cevap

3

İlk iş: Basit typedef, bu olmazsa, matrisi temsil eden bir struct olarak data recasting düşünün ya. İlkini yaptığınızı varsayacağım.

"// do something with data[i][j]"

i, j alır fonksiyonu (a foo ki), ve bağımsız değişken olarak matris struct için bir işaretçi olabilir.

Sonra sadece döngü yapar bir işlevi gerekir: bu bölüm, uygun bir foo için fonksiyon işaretçisi alır ve matris struct işaretçi.

İşiniz, gereksinimlerinize göre çeşitli foo s uygulamaktır.

bunun için değil kullanım makro yapın: onlar zor ayıklama yapmak, bunlar i ve j gibi sabit kodlanmış değişken adları tanıtmak özellikle.

+0

Hmm, sanırım özel ziyaretçileri yapmak için destek bağı gibi bir şeye ihtiyacım var. Yuvalanmış fonksiyonlarla (bir GCC uzantısı olan şu yolun yarısıymışım: http://pastebin.com/3rUz9gEH) Ancak, standart uyumlu iç içe geçmiş kodlar için makrolar kullanmam, ne de kütüphane bağımlılığı gibi http://www.haible.de/bruno/packages-ffcall.html, bkz. eg http://stackoverflow.com/questions/216037/what-tools-are-there-for-functional-programming-in-c. Belki bunun için variadic fonksiyonları kullanmak mümkün mü? – math

+0

Variadic işlevlerle yapılan uygulama şu şekilde görünebilir: http://pastebin.com/N8JtCfve – math

0

İpuçları vermek için Bathsheba'ya teşekkürler, sonunda kendime güvenmediğim fonksiyon göstergelerini içeren çözümler buldum. Asıl sorun, ek parametrelere ihtiyaç duyabilecek belirli fonksiyonların oluşturulmasıdır.

Not: Bu nedenle, joop sayesinde, bir makro çözümü ile atlanabilecek ek bir işlev çağrısına ihtiyacımız var. Örneğin, böyle bir ziyaretçi belirli bir değere sahip tüm matris öğelerini sıfırlar. Başka bir ziyaretçi, elemanları bir dizi parametre ile değiştirebilir veya tek bir parametreye bile gerek duymayabilir. Bu yüzden temel olarak, vizör fonksiyon tipinin esnek bir tanımıyla ilgili soruyla karşılaşıyorum.

BTW: C++ 'da bu, std::bind veya templates ile çözülebilir.

İç içe Fonksiyonlar

İç içe işlevler bir GCC, ve örneğin Clang ile mevcut değil.

typedef double** Matrix;  
typedef void (*MatrixElementVisitor) (double* element); 

void visitMatrixElements(Matrix m, size_t rows, size_t cols, MatrixElementVisitor fn) { 
    for(size_t i = 0; i < rows; ++i) { 
    for(size_t j = 0; j < cols; ++j){ 
     fn(&m[i][j]); 
    } 
    } 
} 

void filM(Matrix m, size_t rows, size_t cols, double val) { 
    void fill(double *element) { 
    *element = val; 
    } 
    visitMatrixElements(m, rows, cols, fill); 
} 

Değişkin fonksiyonları:

typedef double** Matrix; 
typedef void (*MatrixElementVisitor) (double* element, va_list args); 

void visitMatrixElements(Matrix m, size_t rows, size_t cols, MatrixElementVisitor fn, ...) { 
    va_list args,copy; 
    va_start(args, fn); 
    for(size_t i = 0; i < rows; ++i) { 
    for(size_t j = 0; j < cols; ++j){ 
     va_copy(copy, args); 
     fn(&m[i][j], copy); 
     va_end(copy); 
    } 
    } 
    va_end(args); 
} 

void fill(double *element, va_list args) { 
    *element = va_arg(args, double); 
} 

void filM(Matrix m, size_t rows, size_t cols, double val) { 
    visitMatrixElements(m, rows, cols, fill, val); 
} 

geçersiz işaretçi: Yine burada kod örneği

typedef double** Matrix; 
typedef void (*MatrixElementVisitor) (double* element, void *args); 

void visitMatrixElements(Matrix m, size_t rows, size_t cols, MatrixElementVisitor fn, void *args) { 
    if(m) { 
    for(size_t i = 0; i < rows; ++i) { 
     if(m[i]) { 
     for(size_t j = 0; j < cols; ++j){ 
      fn(&m[i][j], args); 
     } 
     } 
    } 
    } 
} 

void fill(double* element, void *args) { 
    if(!args) { 
    return; 
    } 
    *element = *((double*)args); 
} 


void filM(Matrix m, size_t rows, size_t cols, double val) { 
    visitMatrixElements(m, rows, cols, fill, &val); 
} 

Belki başka yolları da var var, ben statik işlevini kullanarak düşünmek değişken fonksiyonlarını da içeren ziyaretçi fonksiyonunun başlatılması için değişkenler.

Geri bildiriminiz için teşekkür ederiz.

+0

Geri arama işlevlerinin satır içi olmayacağını unutmayın, böylece her bir matris öğesi için gerçek bir işlev çağrısı gerekecek. – joop