2016-02-21 26 views
6

Załóżmy, że mam klasę prawdopodobieństwa z metodą, która oblicza średnią tablicy. Ponieważ możliwe jest, że ta metoda zostanie przekazana w postaci tablicy zmiennych, podwójnych, int, itd., Założyłem, że byłoby właściwe, aby ta metoda była metodą szablonową.C++ Jak przekazać wiele parametrów?

Ale przechodząc przez tablicę, muszę zdefiniować typ tablicy i długość tablicy. Moje pytanie brzmi: jak skonfigurować szablon, aby akceptował dwa wejścia? Nawiązałem kontakt z internetem, ale miałem ograniczone szczęście, widząc dobry przykład.

  • Czy można definiować szablony do akceptowania parametrów, które są typu int, float itp.?

I zostały zaksięgowane mojego kodu poniżej

Prawdopodobieństwo Header

#ifndef COFFEEDEVMATH_PROBABILITY_H 
#define COFFEEDEVMATH_PROBABILITY_H 

class Probability 
{ 
    public: 
     Probability(void); 
     template <typename T, int N> 
     void ExpectedValueDataSet(const std::array<T, N>& data) 
     { 
      T test = data[0]; // This is irrelevant, but simply a place holder example. 
     } 

    protected: 
    private: 
}; 

#endif // COFFEEDEVMATH_PROBABILITY_H 

główna

#include <iostream> 
#include <Probability.h> 

int main() 
{ 

    float hoor[] = {3, 3, 1, 1}; 
    Probability prob; 
    prob.ExpectedValueDataSet(hoor, 4); 

} 
+0

to cała klasa, która powinna być szablon, a nie tylko jedna metoda. –

+1

Na początek, 'int' nie jest drugim parametrem szablonu' std :: array', więc nie można go wydedukować. Typ to "size_t". – LogicStuff

+0

Dlaczego dokładnie? Czuję, że bardziej odpowiednie byłoby posiadanie jednego "obiektu prawdopodobieństwa", który może operować na różnego rodzaju danych, które na niego rzucasz. Czy to, co próbuję nie legalnie w C++? – Izzo

Odpowiedz

3

Czy można zdefiniować szablony, aby akceptować parametry typu int, float itp.?

Jest całkowicie w porządku. Ale aby przekazać tablicę, musisz mieć tablicę.

std::array<float,4> hoor2 = {3.0f, 3.0f, 1.0f, 1.0f}; 

W analogicznym szablonie należy wykorzystać size_t nie int

template <typename T, size_t N> 
void ExpectedValueDataSet(const std::array<T, N>& data) {} 

jaki sposób skonfigurować szablon do przyjęcia dwa wejścia?

Wystarczy dodać dodatkowy parametr.Aby przekazać wskaźnik i długości, należy utworzyć szablon, który odbiera wskaźnik i długość

template <typename T> 
void ExpectedValueDataSet(T const * data, int N){} 

Jest też specjalna składnia dla tablic c styl, który pozwoli Ci przekazać je bez konieczności określić długość, ponieważ ten argument zostanie wywnioskowany z typu.

template <typename T, size_t N > 
void ExpectedValueDataSet(const T (&data)[N]) { } 

Razem mamy

class Probability 
{ 
public: 
    template <typename T, size_t N> 
    void ExpectedValueDataSet(const std::array<T, N>& data) {} 

    template <typename T> 
    void ExpectedValueDataSet(T const * data, int N){} 

    template <typename T, size_t N> 
    void ExpectedValueDataSet(const T (&data)[N]){}; 
}; 

Zobacz na żywo exampe roboczą here

+0

Myślę, że jego szablon 'int N' ma być rozmiarem macierzy. – kfsone

+0

@kfsone right, zapomniałem o tablicy stylów c. poprawione. – Thomas

0

Właściwie można mieć wiele argumentów szablonu, ale C++ szablony oferują jeszcze większą elastyczność, ty może bezpośrednio unikać określania, że ​​masz do czynienia z tablicą i przypuszczać, że będziesz miał dostęp doMetoda, typedef i operator[].

To byłoby na tyle, więc kod stanie się coś takiego:

template <typename T> 
void calculate(const T& data) 
{ 
    size_t length = data.size(); 
    using type = typename T::value_type; 
    type value = data[0]; 
    cout << length << " " << value << endl; 
} 

Jest to bardziej ogólne od implementacji, byłoby w stanie pracować ze wszystkimi klasami, które obsługuje wyżej wymienione cechy, nawet nie przejmować jeśli to jest std::array, a może std::vector lub co jeszcze.

+2

W rzeczywistości ogólny sposób radzenia sobie z nim to iteratory. – Puppy

+1

@Puppy: jeśli OP musi radzić sobie z niestandardową strukturą danych, znacznie łatwiej jest zdefiniować metodę 'size()', 'operator []' i 'typedef', które tworzą niestandardowy iterator. Właściwie nauka poprawnego tworzenia iteratora dostępu swobodnego nie jest wcale tak podstawowa. – Jack

+0

Poza tym w zasadzie wszystkie struktury danych już oferują iteratory (i nie bez powodu). – Puppy

3

Problem polega na tym, że zdefiniowałeś swoją tablicę źródłową jako tablicę C na tablicę C zamiast std::array. Jeśli zdefiniujesz swoją tablicę źródłową jako std::array, nie będziesz mieć tego problemu.

Ponadto, nie ma potrzeby, aby dodatkowo przekazywać długość, tak jak w przypadku przykładu.

2

Należy pamiętać, że próbujesz przekazać stary czystym C tablicę float hoor[] funkcjonować z parametrem typu std::array<T,N> który nie jest bezpośrednio kompatybilny z prostą tablicą C.

Prawidłowe składni przechodzą zwykły C tablicy jako odniesienie Przykład

template <size_t N, typename T> 
void ExpectedValueDataSet(const T (&data)[N]) 
{ 
    T test = data[0]; 
} 

Zastosowanie:

float hoor_f[] = {3, 3, 1, 1}; 
ExpectedValueDataSet(hoor_f); 

int hoor_i[] = {3, 3, 1, 1}; 
ExpectedValueDataSet(hoor_i); 
0

Przepuścić pojemnik funkcję matrycy tak.

#include <iostream> 

template<typename T> 
double average(T t) { 
    auto tmp = 0.0; 
    for (auto &i : t) { 
     tmp += i; 
    } 
    return tmp/t.size(); 
} 

using namespace std; 

int main(int argc, char const *argv[]) 
{ 
    auto a = {1.0, 1.1, 1.2, 1.3}; 
    auto b = {2, 3, 4, 5}; 
    auto x = average(a); 
    auto y = average(b); 
    cout << "x: " << x << endl; 
    cout << "y: " << y << endl; 
    return 0; 
} 

X: 1,15
r: 3,5

I stosując lambda. Słowo kluczowe auto w lambdas wymaga C++ 14 i późniejszych.

auto average = [](auto v){ 
    auto tmp = 0.0; 
    for (auto& i : v) { 
     tmp += i; 
    } 
    return tmp/v.size(); 
}; 
auto a = {1.1, 1.2, 1.3, 1.4}; 
auto b = {2, 3, 4, 5, 6, 7, 8, 9}; 
auto x = average(a); 
auto y = average(b); 
cout << "x: " << x << endl; 
cout << "y: " << y << endl; 

x: 1,25
y: 5,5

1

Ostatecznie, mam wrażenie, że po to, czego powinny robić:

template<typename C> 
typename C::value_type average(C const& c) 
{ 
    return std::accumulate(std::begin(c), std::end(c), C::value_type{})/c.size(); 
} 
  1. W miarę możliwości unikaj tablic w stylu C.
  2. Przysługa std::vector w miarę możliwości.
  3. Generyczność wszystkich pojemników od std jest dobra.

Powyższy kod spełnia wszystkie trzy i współpracuje z następującymi przykładami:

std::vector<double> vd = { 0., 1., 3., 4.4 }; 
std::array<float, 4> af = { 3.f, 5.f, 6.f }; 
std::list<int> li = { 1, 2, 3 }; 
Powiązane problemy