2014-05-12 124 views
1

我試圖寫一個模板函數,它接受一個任意容器類具有任意數值類型元素類型:獲取從模板容器類型

template <typename NumType, typename ContType> 
double avg_nums(const ContType<NumType> & data) 
{ 
    double sum = 0; 

    for(ContType::const_iterator iter = data.cbegin(); iter != data.cend(); ++iter) 
    { 
     if(typeid(NumType) == typeid(char) || typeid(NumType) == typeid(unsigned char)) 
     { 
      std::cout << static_cast<int>(*iter) << std::endl; 
     } 
     else 
     { 
      std::cout << *iter << " "; 
     } 

     sum += *iter; 
    } 
    std::cout << std::endl; 

    return sum/data.size(); 
} 

但是這給了語法錯誤(VS2012)。這不起作用或者:

template <typename NumType, typename ContType<NumType> > 
double avg_nums(ContType<NumType> & data) 

我想要的對象類型的容器是一個模板參數,以及容器類型,所以我可以爲NumType的特定情況下增加檢查。如果我改變函數簽名

template <typename NumType, typename ContType> 
double avg_nums(ContType & data) 

它建立,但現在它依賴於明確地指定了正確的模板參數:

std::vector<char> cvec = boost::assign::list_of(0) (1) (1) (2) (3) (5); 
std::vector<int> ivec = boost::assign::list_of(0) (1) (1) (2) (3) (5); 

avg_nums<char, std::vector<char>>(cvec); 
avg_nums<int, std::vector<int>>(ivec); 

如果我改變了簽名

template <typename ContType> 
double avg_nums(ContType & data) 

它的工作原理但現在我沒有直接訪問元素類型。我可以從容器的類型中獲取元素類型(std::vector<int>std::list<unsigned char>)嗎?

回答

3

您可以使用此表:

template <typename ContType> 
double avg_nums(ContType & data) 

然後拿到元素類型

typename ContType::value_type 
1
template <typename ContType> 
double avg_nums(ContType & data) 

它的工作原理,但現在我沒有元素直接訪問類型。我可以從容器的類型(std :: vector或std :: list)中獲取元素類型嗎?

您可以通過嵌套式的方式提取標準集裝箱所包含元素的類型:value_type

typedef typename ContType::value_type NumType; 

我不認爲我會實現這個函數無論如何,因爲你可以使用現有認爲是行之有效的算法:

int value = 0; 
int total = std::accumulate(container.begin(), container.end(), value); 
double avg = total * 1./container.size(); 
0

針對您的特殊當前的問題可以更換

template <typename NumType, typename ContType> 
double avg_nums(const ContType<NumType> & data) 
{ 

template< class ContType > 
double avg_nums(ContType const& data) 
{ 
    using NumType = typename ContType::value_type; 

您將需要一個typename在循環頭類型說明。


更普遍,你可以做

template< template< class, class > class ContType_, class NumType, class Allocator > 
double avg_nums(ContType_<NumType, Allocator> const& data) 
{ 
    using ContType = ContType_<NumType, Allocator>; 

代替

if(typeid(NumType) == typeid(char) || typeid(NumType) == typeid(unsigned char)) 
    { 
     std::cout << static_cast<int>(*iter) << std::endl; 
    } 
    else 
    { 
     std::cout << *iter << " "; 
    } 

你可以只使用隱式的推廣寫字,

std::cout << +*iter << " "; 

或者也許0+*iter如果你發現更清楚。


順帶一提,請考慮使用std::accumulate


另外,順帶一提,請考慮如何處理空容器。


最後,而不是明確的迭代器使用,您只需要使用C++ 11的範圍爲主for

0

如果容器類型不具有某種'value_type'(這是首選方式,因爲這個依賴於值類型是第一個模板參數,它是不一定正確):

// define some custom container where we do not have some kind of 'value_type' 
    template <typename... T> class CustomContainer {}; 

    // forward declare the template function so we can deduce the type in a specialization 
    template <typename ContType> double avg_nums(ContType&); 

    // specialization that deduces ContType and NumType from a single template argument 
    // This works for all continers where the first template argument is the 'value_type' 
    // also note the Ts... which is a placeholder for possible other template arguments that need to be passed on 
    template <template <typename...> class ContType, typename NumType, typename... Ts> 
    double avg_nums(ContType<NumType, Ts...>&) 
    { 
     // so the work 
     return NumType(0); 
    } 

    int main(int,char**) 
    { 
     CustomContainer<int> cont; 
     avg_nums(cont); 
     return 0; 
    }