2016-09-29 207 views
1

我正在創建一個包含數值數據向量(可以是int,float,double等)的模板類。它有一個操作,它在數據上調用std::abs()。像下面的代碼。帶模板參數或類型名稱的模板函數

#include <iostream> 
#include <complex> 
#include <vector> 


template<typename T> class MyData 
{ 
public: 
    std::vector<T> data; 
    MyData<T> my_abs() const; 

}; 


template<typename T> 
MyData<T> MyData<T>::my_abs() const 
{ 
    MyData<T> output; 
    output.data.reserve(data.size()); 
    typename std::vector<T>::const_iterator it; 

    for (it = data.begin(); it != data.end(); it++) 
    { 
     output.data.push_back(std::abs(*it)); 
    } 
    return output; 
} 


int main() 
{ 
    MyData<double> A; 
    A.data = std::vector<double>(10, -1.0); 

    MyData<double> test = A.my_abs(); 

    for (auto el : test.data) 
    { 
     std::cout << el << std::endl; 
    } 
    return 0; 
} 

這對於int,float,double等類型正常工作。我也希望能夠使用這個類的類型,如std::complex<double>

環顧四周,我發現我可以使用模板模板參數:

template<template<typename> class T, typename U> class MyData 
{ 
public: 
    std::vector<T<U>> data; 
    MyData<U> my_abs() const; 

}; 


template<template<typename> class T, typename U> 
MyData<U> MyData<T<U>>::my_abs() const 
{ 
    MyData<U> output; 
    output.data.reserve(data.size()); 
    typename std::vector<T<U>>::const_iterator it; 

    for (it = data.begin(); it != data.end(); it++) 
    { 
     output.data.push_back(std::abs(*it)); 
    } 
    return output; 
} 

前面的代碼不爲我的模板類的工作需要兩個參數,

error: wrong number of template arguments (1, should be 2) 
MyData<U> abs() const; 
    ^

理想情況下,我想是這樣之前的代碼。其中my_abs()函數返回傳遞給我的模板的模板參數的類型。 E.g如果我使用一個std::complex<double>那麼我的主要功能可能看起來是這樣的:

int main() 
{ 
    MyData<std::complex<double>> A; 
    A.data = std::vector<std::complex<double>>(10, std::complex<double>(-1.0, -1.0)); 

    MyData<double> test = A.my_abs(); 

    for (auto el : test.data) 
    { 
     std::cout << el << std::endl; 
    } 
    return 0; 
} 

我不知道如何可以做到這一點(或者甚至可以使用相同的模板類)。

+1

只需專注您的第一個版本,一類像'的std ::複雜'也許。 –

回答

3

您可以在聲明中使用的std::abs(T)返回類型明確地選擇合適的abs


例子:

#include <iostream> 
#include <complex> 
#include <vector> 
#include <cmath> 
#include <utility> 

template<typename T> class MyData 
{ 
public: 
    std::vector<T> data; 
    using abs_type = decltype(std::abs(std::declval<T>())); 
    auto my_abs() -> MyData<abs_type> const; 
}; 

template<typename T> 
auto MyData<T>::my_abs() -> MyData<abs_type> const 
{ 
    MyData<abs_type> output; 
    output.data.reserve(data.size()); 
    typename std::vector<T>::const_iterator it; 

    for (it = data.begin(); it != data.end(); it++) 
    { 
     output.data.push_back(std::abs(*it)); 
    } 
    return output; 
} 

int main() 
{ 
    MyData<std::complex<double>> A; 
    A.data = std::vector<std::complex<double>>(10, std::complex<double>(-1.0, -1.0)); 

    auto test = A.my_abs(); 

    for (auto el : test.data) 
    { 
     std::cout << el << std::endl; 
    } 
    return 0; 
} 
+0

謝謝,這正是我所尋找的。 – DSolis

0

你必須寫您的專業以這種方式

template<template<typename> class T, typename U> 
class MyData<T<U>> // <----- note the <T<U>> 
{ 
public: 
    std::vector<T<U>> data; 
    MyData<U> my_abs() const;  
}; 
+0

爲什麼需要專業化?他的原始模板也適用於'std :: complex '。 – user2296177

+0

@ user2296177 - 因爲OP需要提取'U'類型('double'部分)形式'T '來爲'my_abs()' – max66

+0

@downvoter構造'MyData '返回類型 - 請你能解釋我的答案中有什麼問題? – max66

0

你並不需要爲這個類,模板功能就足夠了。您可以爲您的模板功能提供abs函數,例如

template<typename T, typename F> std::vector<T> my_abs(const std::vector<T> &in, F abs) { 
    std::vector<T> out; 
    for (auto &i: in) { 
     out.push_back(abs(i)); 
    } 

    return out; 
} 

調用此爲

std::vector<int> res = my_abs(in, special_abs); 

,如果您有不同類型的輸入和輸出,可以在TU參數。


正如@ Jarod42已經指出的那樣,這並不爲過載功能,如std::abs工作。 您可以通過給出lambda作爲第二個參數來解決這個問題,例如

std::vector<int> res = my_abs(in, [](const auto& e) { return std::abs(e);}); 

另一個解決方法是通過轉換成正確的類型

std::vector<int> res = my_abs(in, static_cast<double(*)(double)>(std::abs)); 
+1

由於'std :: abs'有過載,'my_abs(in,std :: abs);'不會編譯。 – Jarod42

+0

不幸的是,你是對的。 –

+0

您可能需要'my_abs(in,[](const auto&e){return std :: abs(e);});' – Jarod42