5

Farklı tiplerdeki giriş değişkenlerinin değişken sayısını alan bir C++ şablon fonksiyonu yazmak mümkün mü (girdi sayısı 10 ile sınırlı olabilir)? Örneğin bir sql sorgusu dizesi yürütür ve verilen türden std vektörler sonuçlanan satırları kaydeder bir işlev sql_exec(), yani Şimdi benim naif yaklaşım olmuştur (max ile sınırlı 2 vektörler) olurduC++ değişken bağımsız değişkenli fonksiyonlar

std::vector<double> x,y; 
std::vector<std::string> s; 
std::string query="select * from ..."; 

sql_exec(query, s,x,y); // error if less than 3 rows or conversion not possible 

almak Ben varsayılan argümanlar hakkında işlevini söylemedin ve biz

error: default template arguments may not be used in function templates 

ancak gerçek olsun aptal tabii

struct null_type {}; 
template <typename T1=null_type, typename T2=null_type> 
void sql_query(const std::string& query_str, std::vector<T1>& col1, 
      std::vector<T2>& col2) { 
    ... 
} 

ly gcc ve -std=c++0x ile derler. Ancak, açıkça sql_query() hala değişken uzunluklu giriş almaz ve 2 vektörle çağrılması gerekir. Ayrıca, mevcut derleyicilerin çoğunda taşınabilir bir şey kullanmak istiyorum. Gözardı ettiğim bir şey var mı? Tasarımını değiştirebileceğimi ve belki de boost::tuple ya da başka bir şey kullanabileceğimi biliyorum ama bu kadar basit bir arayüze bayıldım.

+1

Bunu beğendiniz mi? http://en.wikipedia.org/wiki/C%2B%2B0x#Variadic_templates – andrewdski

+0

Evet, teşekkürler. Ancak, C++ 0x'den kaçınmaya çalışıyorum ve aynı zamanda fonksiyonu tanımlamanın tekrarlayıcı yolu da bu durumda işleri zorlaştırıyor. Sınırlı maksimum sayıda girişten memnun olduğum için belki başka bir yol var mı? – tom

+0

, çeşit çeşit şablonların zarifçe kullanılmasının neredeyse bir yolu. Bu tür bir şablona dayalı düşünce alışmak biraz zaman alır, ancak muhtemelen değişken şablonlar olmadan yapacağınız her şeyden çok daha basit olacaktır. –

cevap

4

Yukarıda da belirtildiği gibi, Boost.Preprocessor, C++ 0x kullanılamıyorsa gitmesi gereken yoldur, ancak sözdizimine alışması biraz zaman alır. Aşağıdaki örnek, Boost.Preprocessor'un değişken (ancak sınırlı) sayıdaki argümanlarla fonksiyonları tanımlamak için kullanılabileceğini göstermektedir.

#include <boost/preprocessor/repetition.hpp> 
#include <boost/preprocessor/iteration/local.hpp> 
#include <boost/preprocessor/iteration/iterate.hpp> 

#define MAX_PARAMS 2 

class sql { 
public: 
    // definition of the function in macro form 
    #define SQL_QUERY_DEF(z, n, unused)          \ 
    template <BOOST_PP_ENUM_PARAMS(n, class T)>        \ 
    void query(const std::string& query,         \ 
      BOOST_PP_ENUM_BINARY_PARAMS(n, const T, & x)); 

    // does the actual code replication of SQL_QUERY_DEF 
    #define BOOST_PP_LOCAL_MACRO(n) SQL_QUERY_DEF(~, n, ~) 
    #define BOOST_PP_LOCAL_LIMITS (1, MAX_PARAMS) 
    #include BOOST_PP_LOCAL_ITERATE() 

    ... 
}; 


// two helper functions: 
// expands to var0.clear(); var1.clear(); ... 
#define SQL_VECTOR_CLEAR(z,i,var) var##i.clear(); 
// expands to var0.push_back(this->get_col<T0>(0); ... 
#define SQL_VECTOR_PUSH_BACK(z,i,var) var##i.push_back(this->get_col<T##i>(i)); 

// definition of the function in macro form 
#define SQL_QUERY(z, n, unused)            \ 
template <BOOST_PP_ENUM_PARAMS(n, class T)>         \ 
void sql::query(const std::string& query,          \ 
        BOOST_PP_ENUM_BINARY_PARAMS(n, std::vector< T,>& x)){  \ 
    this->do_query(query);              \ 
    if(this->num_cols()<n){             \ 
     throw std::runtime_error();            \ 
    }                   \ 
    BOOST_PP_REPEAT(n, SQL_VECTOR_CLEAR, x)         \ 
    while(this->is_open()) {             \ 
     BOOST_PP_REPEAT(n, SQL_VECTOR_PUSH_BACK, x)        \ 
     this->step();               \ 
    }                   \ 
} 

// does the actual code replication of SQL_QUERY 
#define BOOST_PP_LOCAL_MACRO(n) SQL_QUERY(~, n, ~) 
#define BOOST_PP_LOCAL_LIMITS (1, MAX_PARAMS) 
#include BOOST_PP_LOCAL_ITERATE() 

önişlemci bu şekilde genişler: BOOST_PP_LOCAL_ITERATE() tabi neden 0 parametrelerle çoğaltma başlar ama biz 1'den başlamak gerekir burada biz BOOST_PP_REPEAT(MAX_PARAMS, SQL_QUERY, ~) kullanamaz,

$ g++ -P -E sql.cpp | astyle 

class sql { 
public: 
    template < class T0> void query(const std::string& query, const T0 & x0); 
    template < class T0 , class T1> void query(const std::string& query, const T0 & x0 , const T1 & x1); 
    ... 
}; 
template < class T0> void sql::query(const std::string& query, std::vector<T0>& x0) { 
    this->do_query(query); 
    if(this->num_cols()<1) { 
     throw std::runtime_error(); 
    } 
    x0.clear(); 
    while(this->is_open()) { 
     x0.push_back(this->get_col<T0>(0)); 
     this->step(); 
    } 
} 
template < class T0 , class T1> void sql::query(const std::string& query, std::vector<T0>& x0 , std::vector<T1>& x1) { 
    this->do_query(query); 
    if(this->num_cols()<2) { 
     throw std::runtime_error(); 
    } 
    x0.clear(); 
    x1.clear(); 
    while(this->is_open()) { 
     x0.push_back(this->get_col<T0>(0)); 
     x1.push_back(this->get_col<T1>(1)); 
     this->step(); 
    } 
} 

Not, işte hangi daha esnektir.

6

C++ 0x'de bu, variadic şablonlar aracılığıyla başarıldı (ve argümanların sayısı çok büyük olabilir, sınırlama uygulamaya özgüdür).

C++ 03'te bu, çeşitli aritmetik şablon işlevlerinin çoğunu oluşturan önişlemci makrolara sahip olarak taklit edilir (bkz. Boost.Preprocessor).

1'den 10'a kadar argümandan "bağlama" oluşturmak için C++ 03 tekniğini kullandım ve oldukça iyi çalışıyor.