2015-10-10 5 views
1

Я пытаюсь написать простой шаблон функции в C++, в котором я печатаю значение переменной неизвестного типа. Проблема в том, что я не могу понять, как это сделать, поскольку переменная может быть либо указателем, либо примитивным типом. С примитивным типом я могу просто распечатать значение; но указатели требуют де-ссылки.Печать значения переменной неизвестного типа?

Следующий код дает мне ошибку:

#include <iostream> 
#include <type_traits> 

using namespace std; 

template<typename T> 
void foo(T someVar) { 
    if(std::is_fundamental<T>::value) { 
    cout << "It's primitive! \n" << someVar << endl; 
    } else { 
    cout << "It's a pointer! \n" << *someVar << endl; 
    } 
} 

int main(int argc, char **argv) { 
    int x = 5; 
    foo(x); 

    int *y = new int(); 
    *y = 5; 

    foo(y); 
    delete y; 

    return 0; 
} 

Я получаю ошибку при компиляции является:

test.cc: In function 'void foo(T) [with T = int]': 
test.cc:19:8: instantiated from here 
test.cc:13:5: error: invalid type argument of unary '*' (have 'int') 

Он жалуется, что я пытаюсь разыменовываются примитивный тип из мой первый вызов foo(), но именно поэтому я использую if-statement: для проверки, является ли он примитивным или нет. Как я могу реализовать то, что я пытаюсь сделать?

ответ

3

Что вам нужно сделать, это написать 2 версии вашей шаблонной функции.

template<typename T> 
void foo(T someVar) { 
    cout << "Assume it's primitive! \n" << someVar << endl; 
} 

template<typename T> 
void foo(T* pVar) { 
    cout << "This is a pointer! \n" << *pVar << endl; 
} 

Компилятор выберет версию указателя, если она будет работать, потому что это более конкретно. Если тип не является (необработанным) указателем, по умолчанию будет использоваться первая версия.

Если вам нужны интеллектуальные указатели, подлежащие разыменованию, вы можете дополнительно перегрузить определение своей функции.

Например.

template<typename T> 
void foo(std::shared_ptr<T> pVar) { 
    cout << "This is a shared pointer! \n" << *pVar << endl; 
} 
+0

Это не частичные специализации, а фактически перегрузки. Если вы думаете о них как о частичной специализации, [вы можете получить наибольшее удивление] (http://www.gotw.ca/publications/mill17.htm). – 5gon12eder

2

Вам нужен дополнительный слой косвенности.

#include <iostream> 

template < typename T > 
struct print_helper 
{ 
    static void 
    print(std::ostream& os, const T& value) 
    { 
    os << "The value is " << value << "\n"; 
    } 
}; 

template < typename T > 
struct print_helper< T * > 
{ 
    static void 
    print(std::ostream& os, const T *const pointer) 
    { 
    os << "The pointer points to " << *pointer << "\n"; 
    } 
}; 

template < typename T > 
void 
foo(T whatever) 
{ 
    print_helper<T>::print(std::cout, whatever); 
} 


int 
main() 
{ 
    const auto a = 42; 
    foo(a); 
    foo(&a); 
} 

Выход:

The value is 42 
The pointer points to 42 
1

Написать функцию дважды:

struct Foo 
{ 
    template<typename T> 
    static void foo(T val) { 
     cout << "var: " << val << endl; 
    } 

    template<typename T> 
    static void foo(T* val) { 
     cout << "ptr: " << *val << endl; 
    } 
}; 

Для вызова:

int x; 
int *y; 
Foo::foo(x); 
Foo::foo(y); 
1

Раствор, я неравнодушен к для печати только красиво это написать функцию, чтобы сделать дрефера encing.

template<typename T> T &deref(T &elem) { return elem; } 
template<typename T> T &deref(T *elem) { return *elem; } 

Тогда вы можете просто использовать deref(value) в любом месте вы не знаете, будет ли value быть указателем, до тех пор, пока вы не заботитесь, которые она.

template<typename T> 
void print(T t) { 
    std::cout << deref(t) << '\n'; 
} 
Смежные вопросы