1

I have a project (A) that uses a class from another (B), but inluding B's header makes the compilation of A very messy, while separate compilation works fine (but in that case I can't use B's class in A).

B is compiled with VS2019's compiler v142, A is compiled with cuda 10's nvcc.

How can I forward declare only few members eg., a constructor, a property and a method ?

In A, I would like to uses this code without B's header:

DX12Cuda = new DX12CudaInterop(ImUtil.ImFeatures.Width, ImUtil.ImFeatures.Height, L"DX12Cuda", funcMessage);
DX12Cuda->CuSurfaceUpdater = [&](cudaSurfaceObject_t o) {UpdateCuSurface(o); };
OnRenderDX12 = [&]() {DX12Cuda->OnRender(); };
DX12Cuda->OnInit(hwnd);

In B:

class DX12CudaInterop
{
public:
    DX12CudaInterop(UINT width, UINT height, wstring name, MessageChangedCallback managedDelegate);
    function<void(cudaSurfaceObject_t)> CuSurfaceUpdater;
    OnInit(HWND hwnd);
    OnRender();
}

void DX12CudaInterop::OnInit(HWND hwnd) {/*...*/}
void DX12CudaInterop::OnRender() {/*...*/}

examples of errors:

Severity Code Description Project File Line Suppression State Error identifier "NPP_MIRROR_FLIP_ERR" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\helper_cuda.h 412 Error name followed by "::" must be a class or namespace name ShCuSum path_to_solution\D3D12CudaUpdateFull\DXSampleHelper.h 3
Error identifier "byte" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\DXSampleHelper.h 29
Error name followed by "::" must be a class or namespace name ShCuSum path_to_solution\D3D12CudaUpdateFull\DXSampleHelper.h 31
Error name followed by "::" must be a class or namespace name ShCuSum path_to_solution\D3D12CudaUpdateFull\DXSampleHelper.h 41
Error expected a ";" ShCuSum path_to_solution\D3D12CudaUpdateFull\DXSampleHelper.h 41
Error identifier "file" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\DXSampleHelper.h 42
Error identifier "byte" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\DXSampleHelper.h 52
Error inline specifier allowed on function declarations only ShCuSum path_to_solution\D3D12CudaUpdateFull\DXSampleHelper.h 63
Error incomplete type is not allowed ShCuSum path_to_solution\D3D12CudaUpdateFull\DXSampleHelper.h 63
Error identifier "ID3D12Object" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\DXSampleHelper.h 63
Error identifier "pObject" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\DXSampleHelper.h 63
Error expected a ")" ShCuSum path_to_solution\D3D12CudaUpdateFull\DXSampleHelper.h 63
Error expected a ";" ShCuSum path_to_solution\D3D12CudaUpdateFull\DXSampleHelper.h 64
Error identifier "IDXGIFactory2" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\DX12CudaSample.h 30
Error identifier "IDXGIAdapter1" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\DX12CudaSample.h 30
Error identifier "NPP_BAD_ARG_ERROR" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\helper_cuda.h 323 Error identifier "NPP_COEFF_ERROR" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\helper_cuda.h 326 Error identifier "NPP_RECT_ERROR" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\helper_cuda.h 329 Error identifier "NPP_QUAD_ERROR" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\helper_cuda.h 332 Error identifier "NPP_MEM_ALLOC_ERR" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\helper_cuda.h 335 Error identifier "NPP_HISTO_NUMBER_OF_LEVELS_ERROR" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\helper_cuda.h 338 Error identifier "NPP_INVALID_INPUT" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\helper_cuda.h 341 Error identifier "NPP_POINTER_ERROR" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\helper_cuda.h 344 Error identifier "NPP_WARNING" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\helper_cuda.h 347 Error identifier "NPP_ODD_ROI_WARNING" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\helper_cuda.h 350 Error identifier "NPP_MEMFREE_ERR" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\helper_cuda.h 403 Error identifier "NPP_MEMSET_ERR" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\helper_cuda.h 406 Error identifier "NPP_MEMCPY_ERR" is undefined ShCuSum path_to_solution\D3D12CudaUpdateFull\helper_cuda.h 409 Error (active) E0135 class "Microsoft::WRL::Details::EnableIf" has no member "type" D3D12CudaUpdate C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\winrt\wrl\client.h 379

Soleil
  • 6,404
  • 5
  • 41
  • 61
  • You can't. Maybe we can help if you explain the problem behind it. I.e. can the definitions (not declarations!) of `A` go into the cpp file? – n314159 Dec 10 '19 at 20:37
  • 1
    I think you will have to create a minimal example. And perhaps mention the compiler you are using. – drescherjm Dec 10 '19 at 20:37
  • please provide a [mcve] – 463035818_is_not_an_ai Dec 10 '19 at 20:37
  • You basically can't. Standard practice is forward declare the class in the header file of the class that needs it, and then in the CPP file for the class that needs it then you include the relevant header file. Basically you need [this](https://stackoverflow.com/questions/625799/resolve-build-errors-due-to-circular-dependency-amongst-classes) – NathanOliver Dec 10 '19 at 20:38
  • 1
    What does "makes the compilation...very messy" mean? Can you give more detail about the problem that you are trying to solve? Showing some code might help. – Solomon Slow Dec 10 '19 at 20:40
  • Maybe you want some type of wrapper class that hides the implementation detail completely. – drescherjm Dec 10 '19 at 20:46
  • @drescherjm How would you do that ? – Soleil Dec 10 '19 at 21:05
  • Maybe through PIMPL. [https://cpppatterns.com/patterns/pimpl.html](https://cpppatterns.com/patterns/pimpl.html) – drescherjm Dec 10 '19 at 21:06

1 Answers1

3

You can’t. Here’s what you can do instead:

// interop.h, shared across the project
class iCudaInterop
{
public:
    virtual ~iCudaInterop() { }
    virtual void OnInit( HWND hwnd ) = 0;
    virtual void OnRender() = 0;
};
extern std::unique_ptr<iCudaInterop> createInterop( UINT width, UINT height, const std::wstring& name, MessageChangedCallback del );

// interop.cpp, only in project B
#include "interop.h"

class CudaInterop : public iCudaInterop
{
    DX12CudaInterop m_impl;

public:
    CudaInterop( UINT width, UINT height, const std::wstring& name, MessageChangedCallback del ) :
        m_impl( width, height, name, del ) { }
    ~CudaInterop() = default;

    void OnInit( HWND hwnd ) override { m_impl.OnInit( hwnd ); }
    void OnRender() override { m_impl.OnRender(); }
};

std::unique_ptr<iCudaInterop> createInterop( UINT width, UINT height, const std::wstring& name, MessageChangedCallback del )
{
    return std::make_unique<CudaInterop>( width, height, name, del );
}

For that property, the easy way is wrap into 2 more abstract methods of iCudaInterop interface, getter and setter, in the implementation get/set the field of m_impl.

Soonts
  • 20,079
  • 9
  • 57
  • 130
  • Is is OK to assign a smart pointer to a field ? Does its "out of scope" hence deleter will be called when the field's class will also be deleted ? – Soleil Dec 11 '19 at 20:24
  • 1
    @Soleil Generally yes, but you need to keep lifetime in mind. `std::unique_ptr` is a single owner of the class instance. When the smart pointer is destroyed (out of scope if it’s a local variable, or destructor for a class field) the referenced object will be destroyed as well. You can use `std::move` or `unique_ptr::swap` to transfer the ownership to another smart pointer. – Soonts Dec 12 '19 at 20:39