문제

I'm using the CRTP pattern to create an interface, which other classes will derive from.

In the interface I forward declare a structure (important because I don't want to drag other stuff in the interface), but I include its definition in the cpp file which defines the interface.

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();
}

And this is the implementation which implements the interface

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;
}

And the main file

#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;
}

I get linking errors on both VS and GCC.

Any workaround? Thank you.

도움이 되었습니까?

해결책

There is a flaw in your very approach: You have a public function returning a ForwardDecl instance, so every client wanting to use this function also must include the according definition of that type, which implies you can make that type public from the beginning. This includes making the function definition inline, which will fix your linker problems.

However, if you really want to hide the content of that structure and you are sure clients don't need it directly, you can declare it and then pass around references to such a structure (or pointers, but raw pointers are evil albeit not in the same league of evil as #macros). In that case, I would still make the function definition inline.

If you really, really want to not make the function inline, you can also explicitly instantiate the function template for the types that you need. You would add at the end of the template's .cpp file something like template class Interface<int>; (I don't remember the exact syntax so take that with a few flakes of fleur de sel, check out the C++ FAQ at parashift.com for more info). This makes the template a little less universal though, as it requires adjustments for any type that you want to use it with, but it can be an approach in some corner cases.

다른 팁

The definitions of function templates and member functions of class templates need to be visible in all translation units that instantiate those templates. That is, you shouldn't put template definitions in a .cpp file, which means you need to move the contents of Interface.cpp up into Interface.h.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top