2014-09-14 19 views
5

Farklı veri türlerinin çoklu argümanlarını kabul eden ve sayıların toplamını döndüren bir işlev yazmaya çalışıyorum. Toplam için hangi veri türünün kullanılacağına karar verebilmelidir. Örneğin Ekleme (3,1,2,3) yazarsam, toplamı int olarak döndürmelidir. Ancak, eğer (3,1,2,5,3,25) ekle yazarsam, toplamı bir çifte döndürmelidir.Değişken sayıların eklenmesi

Şablon kullanmayı denedim, ancak derleme zamanı hatası veriyordum. İşte fonksiyonu

template <typename T> 
T add(int n, ...) 
{ 
    T sum = 0; 
    va_list vl; 
    va_start(vl,n); 
    for(int i=0;i<n;i++) 
    { 
     sum += va_arg(vl,T); 
    } 
    va_end(vl); 
    return sum; 
} 
int main() 
{ 
    std::cout<<add(3,1,2,3); 
    return 0; 
} 

Derleme Hatası şudur: 'ekleyin (int, int, int, int)' çağrısına için eşleşen fonksiyonu. Sanırım hata geliyor çünkü va_arg T'den geçtim, ama genelleştirilmek için başka ne geçeceğimi bilmiyorum. (Int n, ...)

kullanım T ekleyin::

+4

Neden [Varidaic Templates] kullanmıyorsunuz (http: // www.cplusplus.com/articles/EhvU7k9E/)? –

+0

Geçtiğimizde bu sorunu çözüyor argümanlar tamsayılar, ancak çift değerleri geçerken yanlış cevap veriyor. –

+0

@DarshilBabel hayır, işe yarıyor. [** Canlı yayınlayın **] (http://ideone.com/ggLxjO) – WhozCraig

cevap

-2

i sorun int yerine

kullanmaya çalışırken, parametre türünü belirledikten olduğunu düşünüyorum T (T n ekleyin .. .)

+0

Sanırım 'n' –

+0

sayım n ilk argüman ismidir –

+0

@MohitJain Şüpheleyim ki, bu çok değişkenlikli bir rotaya giderseniz çok az anlam ifade eder, çünkü [' sizeof ... ' ] (http: //en.cppreference.com/w/cpp/language/sizeof ...) ve gerekirse biraz matematik. – WhozCraig

2

Sen değiştirmeniz gerekir

std::cout<<add(3,1,2,3); 

std::cout<<add<int>(3,1,2,3); // explicitly, int, double, float whatever 
ile

Derleyici, örtülü çağrıda typename değerini çıkaramadığı için kodun başarılı bir şekilde çalışması için.

İşleviniz, T türünün değerini döndürür, ancak T türünde herhangi bir argüman belirtmezsiniz, bu da derleyicinin türden çıkmasını imkansız kılar.


Diğer çözüm add(0) için çalışan bir aşırı eklemek ve tip T ait eklenti ilk argüman geçmek olacaktır. Bu OP'nin örtülü kesinti hedefine ulaşabilir. Şimdi derleyici, ilk argümandan dönüş türünü alabilir.

#include <cstdarg> 
#include <iostream> 
#include <cassert> 
using namespace std; 

int add(int n) 
{ 
    assert(0 == n); 
    return 0; 
} 

template <typename T> 
T add(int n, T first, ...) 
{ 
    T sum = first; 
    va_list vl; 
    va_start(vl,first); 
    for(int i=1;i<n;i++) 
    { 
     sum += va_arg(vl,T); 
    } 
    va_end(vl); 
    return sum; 
} 
int main() 
{ 
    std::cout<<add(3,1,2,3); 
    std::cout<<add(3,1.5,2.,3.5); 
    return 0; 
} 

live code here

+0

OP'nin sorusuna yaptığı bir yorumda belirtmiş olduğum gibi, bu, çalışma zamanı sırasında geri dönüş türünü belirleme amacına hemen hemen son veriyor. Mantıksal olarak düşünürsek, polimorfizm kullanmadan bunu yapmanın (çalışma zamanı sırasında geri dönüş türünü belirleme) bir yolu yoktur. –

+0

Bir geçici çözüm, (T) eklemek için çalışan bir aşırı yüklenmenin doğru olması ve T türünün ekinde ilk bağımsız değişkenin iletilmesidir. Bu, OP'nin örtülü kesinti hedefine ulaşabilir. –

+0

Yani * yazmak * (değil * sağ *) ... Ve önerinizin nasıl çalıştığını göremiyorum. Eğer düşünürseniz, cevabı ona eklemek isteyebilirsiniz. –

2

Why don't you use Varidaic Templates ? – Mohit Jain

sen yazabilirsiniz ise C++ 14:

template<typename T> 
inline T sum(T t){ 
    return t; 
} 

template<typename T, typename... Ts> 
inline auto sum(T t, Ts... ts){ 
    return t+sum(ts...); 
} 

#include<iostream> 
int main(){ 
    std::cout<<sum(2.5, 2)<<'\n' 
      <<sum(2, 2.5)<<'\n' 
      <<sum(1u, 2.5, 3.f, '0')<<'\n'; 
} 

C++ 11 MSVC altında yazarsanız ++ (it doesn't work under g++):

template<typename T> 
inline T sum(T t){ 
    return t; 
} 

template<typename T, typename... Ts> 
inline auto sum(T t, Ts... ts)->decltype(t+sum(ts...)){ 
    return t+sum(ts...); 
} 

#include<iostream> 
int main(){ 
    std::cout<<sum(2.5, 2)<<'\n'   //works 
      <<sum(2, 2.5)<<'\n'   //works 
      <<sum(1u, 2.5, 3.f, '0')<<'\n';//works under VC++, but not under g++ 
} 
+1

'std :: common_type' kullanabilirsiniz. (ve ilk önce promosyonu zorlamak, toplam için * tuhaf * sonucundan sakınmak olabilir (int (42), char (127), char (127), char (2)) '((298 yerine 42)). – Jarod42

+0

Sadece [std :: common_type 'kullanıldığında '' 298' yerine 42'' (http://rextester.com/QNCHB76405) kullanılır. – GingerPlusPlus

+0

uint32_t vs uint32_t ile başka bir örnek http://rextester.com/OKA3142 – Jarod42

İlgili konular