2016-10-26 5 views
1

Я пытаюсь написать класс, который в простейшем примере работает следующим образом:Как исправить этот шаблон класса

// Example program 
#include <iostream> 
#include <complex> 
#include <typeinfo> 

template<typename NumberType> 
class SomeClass 
{ 
    public: 
     SomeClass(NumberType a_) : a(a_) {} 
     void get_number() 
     { 
      if (typeid(NumberType) == typeid(std::complex<double>)) 
       std::cout << a.real() << " " << a.imag() << std::endl; 
      else 
       std::cout << a << std::endl; 
     } 
    private: 
     NumberType a; 
}; 

int main() 
{ 
    int a=1; 
    std::complex<double> c(2.0,3); 

    SomeClass<int> A(a);  
    A.get_number(); 

    SomeClass<std::complex<double>> C(c); 
    C.get_number(); 

    return 0; 
} 

Это в основном печатает любое действительное число, как это, но он должен разделить комплексное число в два двух реала.

Если я скомпилировать его, как это показано, сообщение об ошибке выглядит следующим образом

In instantiation of 'void SomeClass<NumberType>::get_number() [with NumberType = int]': 
28:18: required from here 
14:46: error: request for member 'imag' in '((SomeClass<int>*)this)->SomeClass<int>::a', which is of non-class type 'int' 
14:27: error: request for member 'real' in '((SomeClass<int>*)this)->SomeClass<int>::a', which is of non-class type 'int' 

Я понимаю, что с a имеет тип int в первом случае, я не могу использовать imag() на нем, следовательно, сообщение об ошибке.

Как я могу изменить этот класс, чтобы он делал то, что мне нужно в случае произвольных аргументов шаблона ?

ответ

2

Вы должны использовать шаблоны и специализацию шаблонов, а не typeid -в C++ вы хотите использовать абстракции времени компиляции, а не принимать решения времени выполнения относительно типа переменной или значения.

Вы можете иметь следующие автономные вспомогательные функции:

// General case: 
template <typename T> 
void get_number(const T& value) 
{ 
    std::cout << value << std::endl; 
} 

// Specialization for complex<double> 
template <> 
void get_number<std::complex<double> >(const std::complex<double>& value) 
{ 
    std::cout << value.real() << " " << value.imag() << std::endl; 
} 

// ... More specializations if you need to. 

Теперь вы можете позвонить:

get_number(3); 
get_number(std::complex<double>(1, 2)); 

Чтобы сделать его более универсальным, вы можете использовать std::complex<T> вместо std::complex<double>. Это требует немного больше работы, потому что частичная специализация шаблона функций не поддерживается. Вам нужно сделать get_number статического члена хелпер структуры следующим образом:

// General case: 
template <typename T> 
struct get_number_helper { 
    static void get(const T& value) 
    { 
     std::cout << value << std::endl; 
    } 
}; 

// Specialization for complex<T> 
template <typename T> 
struct get_number_helper<std::complex<T> > { 
    static void get(const std::complex<T>& value) 
    { 
     std::cout << value.real() << " " << value.imag() << std::endl; 
    } 
}; 

template<typename T> 
void get_number(const T& value) 
{ 
    get_number_helper<T>::get(value); 
} 
2

Как alexc уже упоминалась, вы должны использовать спецификации шаблона, чтобы предотвратить компилятор смstd::complex<>::real или imag члена при использовании int или double как тип данных.

член спецификации шаблона ближе к тому, что у вас уже есть:

// Example program 
#include <iostream> 
#include <complex> 

template<typename NumberType> 
class SomeClass 
{ 
public: 
    SomeClass(NumberType a_) : a(a_) {} 
    void get_number() { 
     std::cout << a << std::endl; 
    } 

private: 
    NumberType a; 
}; 

template<> 
void SomeClass<std::complex<double> >::get_number() { 
    std::cout << a.real() << " " << a.imag() << std::endl; 
} 

int main() 
{ 
    int a=1; 
    std::complex<double> c(2.0,3); 

    SomeClass<int> A(a);  
    A.get_number(); 

    SomeClass<std::complex<double> > C(c); 
    C.get_number(); 

    return 0; 
} 
Смежные вопросы