2014-04-15 4 views
1

Я пытаюсь сделать пример использования шаблонов, чтобы узнать, как их использовать. Я сделал проект в Visual Studio 2010 C++ с тремя файлами:Почему этот код шаблона шаблона не компилируется?

controller.cpp:

#include <iostream> 

#include "Foo.h" 

using namespace std; 

int main(){ 

    Example<int,string> example; 

    example.appols(5, "Hi"); 

    return 0; 
} 

foo.h:

#include <iostream> 

using namespace std; 

template <class T, class E> 
class Foo{ 
public: 
    void printThis(T t, E e); 
}; 

template <class T, class E> 
class Example{ 
public: 
    void appols(T t, E e); 
}; 

Foo.ipp:

#include <iostream> 

#include "Foo.h" 

using namespace std; 

template<class T, class E> 
void Foo<T, E>::printThis(T t, E e){ 
    cout << "FOO! " << t << ' ' << e << endl; 
} 

template<class T, class E> 
void Example<T, E>::appols(T t, E e){ 
    cout << "APPOLS!! " << t << ' ' << e << endl; 
    Foo<T,E> f; 
    f.printThis(t,e); 
} 

Когда я пытаюсь скомпилировать, я получаю:

1>------ Build started: Project: Template Practive, Configuration: Debug Win32 ------ 
1>Controller.obj : error LNK2019: unresolved external symbol "public: void __thiscall Example<int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >::appols(int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" ([email protected][email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@Z) referenced in function _main 
1>C:\Users\Matthew\documents\visual studio 2010\Projects\Template Practive\Debug\Template Practive.exe : fatal error LNK1120: 1 unresolved externals 
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== 

Не могли бы вы помочь мне увидеть, что я сделал неправильно здесь и откуда error LNK2019? Спасибо заранее!

+1

После определения класса вам нужно включить 'Foo.ipp' в' Foo.h'. – juanchopanza

ответ

5

Дешифровка Сообщение об ошибке

Попытаемся расшифровать сообщение об ошибке первое:

1>Controller.obj : error LNK2019: unresolved external symbol 
"public: void __thiscall Example<int,class std::basic_string<char,struct 
std::char_traits<char>,class std::allocator<char> > >::appols(int,class 
std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" 
([email protected][email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@Z) 
referenced in function _main 

Мы можем начать, чтобы уменьшить соотношение шум/сигнал в сообщении об ошибке.

Часть с ([email protected][email protected][email protected][email protected]@[email protected]@... - это только C++ название mangling. Он предназначен для компилятора C++, и это не значит, что он доступен для человека. Поэтому мы можем просто отказаться от него.

Упрощенное сообщение об ошибке будет выглядеть так:

1>Controller.obj : error LNK2019: unresolved external symbol 
"public: void __thiscall Example<int,class std::basic_string<char,struct 
std::char_traits<char>,class std::allocator<char> > >::appols(int,class 
std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" 
referenced in function _main 

Первая строка говорит нам, что есть "неразрешенный внешний символ". Давайте попробуем идентифицировать его, глядя на следующие строки.

Части:

class std::basic_string<char,struct std::char_traits<char>... 

только длинное имя std::string (что соответствует std::basic_string шаблон с char как тип характера и использование по умолчанию char черты в и аллокатора по умолчанию).

Таким образом, мы можем еще больше снизить уровень шума, подставляя std::string вместо этих многословных частей:

1>Controller.obj : error LNK2019: unresolved external symbol 
"public: void __thiscall Example<int,string>::appols(int,string)" 
referenced in function _main 

Теперь ошибка гораздо яснее.

Часть __thiscall - это просто соглашение о вызове, используемое по умолчанию для функций-членов C++.

Таким образом, компоновщик жалуется об этом методе:

"public: void Example<int,string>::appols(int,string)" 

, который соответствует вашей Example<T,E>::appols():

template <class T, class E> 
class Example{ 
public: 
    void appols(T t, E e); 
}; 

когда T=int и E=std::string.

Это соответствует тому, что у вас есть в вашей main() функции в controller.cpp:

Example<int,string> example; 

example.appols(5, "Hi"); 

Диагностика и решение проблемы

Проблема заключается в том, что все исходный код шаблона должен быть в заголовочных файлах, а не в .cpp-файлах.

На самом деле компилятору необходимо определить код шаблона для его создания.

Таким образом, вы можете переместить код из файла Foo.ipp в foo.h (или просто #include "Foo.ipp" от вашего foo.h), и добавить inline к определениям функций шаблона:

// New code in Foo.h 

template<class T, class E> 
inline void Foo<T, E>::printThis(T t, E e){ 
    cout << "FOO! " << t << ' ' << e << endl; 
} 

template<class T, class E> 
inline void Example<T, E>::appols(T t, E e){ 
    cout << "APPOLS!! " << t << ' ' << e << endl; 
    Foo<T,E> f; 
    f.printThis(t,e); 
} 

Отметим также что using namespace std; действительно плохо в файлах заголовков, так как это загрязнит глобальное пространство имен для всех клиентов, которые содержат ваши заголовки. Просто используйте префикс std:: явно в файлах заголовков (например, std::cout, std::endl и т. Д.).