2013-04-08 2 views
2

Я использую шаблон CRTP для создания интерфейса, из которого будут извлекаться другие классы.CRTP, форвардные декларации и шаблоны в файлах cpp

В интерфейсе I forward объявляет структуру (важно, потому что я не хочу перетаскивать другой материал в интерфейсе), но я включаю его определение в файл cpp, который определяет интерфейс.

Interface.h

#ifndef INTERFACE_H_INCLUDED 
#define INTERFACE_H_INCLUDED 

// forward declaration 
class ForwardDecl; 

template <class Derived> 
class Interface 
{ 
public: 
    ForwardDecl interfaceMethod(); 

}; 

#endif // INTERFACE_H_INCLUDED 

ForwardDecl.h

#ifndef FORWARDDECL_H_INCLUDED 
#define FORWARDDECL_H_INCLUDED 

struct ForwardDecl 
{ 
    ForwardDecl(int i):internal(i) 
    {} 

    int internal; 
}; 

#endif // FORWARDDECL_H_INCLUDED 

Interface.cpp

#include "Interface.h" 
#include "ForwardDecl.h" 

template<class Derived> 
ForwardDecl Interface<Derived>::interfaceMethod() 
{ 
    return static_cast<Derived *>(this)->implementation_func(); 
} 

И это я mplementation, который реализует интерфейс

Implementation.h

#ifndef IMPLEMENTATION_H_INCLUDED 
#define IMPLEMENTATION_H_INCLUDED 
#include "Interface.h" 
class ForwardDecl; 

class Implementation: public Interface<Implementation> 
{ 
    friend class Interface<Implementation>; 
private: 
    ForwardDecl implementation_func(); 

}; 


#endif // IMPLEMENTATION_H_INCLUDED 

Implementation.cpp

#include "Implementation.h" 
#include "ForwardDecl.h" 
#include <iostream> 
struct ForwardDecl Implementation::implementation_func() 
{ 
    ForwardDecl fd(42); 
    std::cout << fd.internal << std::endl; 

    return fd; 
} 

И главный файл

#include <iostream> 
#include "Implementation.h" 
#include "ForwardDecl.h" 
using namespace std; 

int main() 
{ 
    Implementation impl; 

    ForwardDecl fd = impl.interfaceMethod(); 
    cout << fd.internal << endl; 
    return 0; 
} 

Я получаю ссылки ошибки s на VS и GCC.

Любое обходное решение? Спасибо.

+0

Возможный дубликат [Почему шаблоны могут быть реализованы только в файле заголовка?] (Http: // stackoverflow.com/questions/495021/why-can-templates-only-be-implement-in-the-header-file) – WhozCraig

+0

Выполнение работы декларации в интерфейсе является основным моментом здесь, если бы не это, я бы переместите все в заголовочный файл. – farnsworth

+0

То, что вы пытаетесь сделать (если я это понимаю, что-то вроде iffy), возможно, возможно с помощью определения * указателя и указателя шаблона *, но такого уровня экземпляра мне нелегко видеть, как он работает. – WhozCraig

ответ

1

Существует недостаток в вашем самом подходе: у вас есть публичная функция, возвращающая экземпляр ForwardDecl, поэтому каждый клиент, желающий использовать эту функцию, также должен включать соответствующее определение этого типа, что подразумевает, что вы можете сделать этот тип public из начало. Это включает в себя определение функции inline, которая поможет устранить проблемы с компоновщиками.

Однако, если вы действительно хотите скрыть содержимое этой структуры, и вы уверены, что клиенты не нуждаются в ней напрямую, вы можете объявить ее, а затем передать ссылки на такую ​​структуру (или указатели, но исходные указатели зло, хотя и не в той же лиге зла, что и #macros). В этом случае я все же сделаю определение функции inline.

Если вы действительно хотите не выполнять функцию inline, вы также можете явно создать шаблон функции для тех типов, которые вам нужны. Вы добавили бы в конец файла .cpp шаблона что-то вроде template class Interface<int>; (я не помню точного синтаксиса, так что сделайте это с несколькими хлопьями де-ла-де-сель, посмотрите C++ FAQ at parashift.com for more info). Это делает шаблон немного менее универсальным, хотя он требует корректировки для любого типа, с которым вы хотите его использовать, но это может быть подход в некоторых случаях.

+0

yup исправил это некоторое время назад после прочтения FAQ по parashift, так как ваш ответ был верным, вы получили очки :) – farnsworth

1

Определения шаблонов функций и функций-членов шаблонов классов должны быть видимыми во всех единицах перевода, которые создают эти шаблоны. То есть вы не должны указывать определения шаблонов в файле .cpp, что означает, что вам нужно переместить содержимое Interface.cpp в Interface.h.

+0

Да, но если я это сделаю, я должен # включить «ForwardDecl.h», и ** это то, чего я пытаюсь избежать. – farnsworth

Смежные вопросы