Skip to content

Add forward declaration header #328

@breyerml

Description

@breyerml

In our code, I stumbled upon a problem, where we couldn't include the sycl/sylc.hpp header in a public API header.

A simple example showing the problem:
foo.hpp

#include "sycl/sycl.hpp"

void foo(const sycl::queue& q);

foo.cpp

#include "foo.hpp"

void foo(const sycl::queue& q) {
    // do something with the sycl::queue
    q.get_device().template get_info<sycl::info::device::name>();
}

This example has one major drawback: the sycl/sycl.hpp header has to be included in a public API header, leaking all of its implementation to said public API.

The easiest way to prevent this is to forward declare the sycl::queue:
foo.hpp

namespace sycl {
    class queue;
}

void foo(const sycl::queue& q);

However, this is currently not possible (at least for DPC++ and hipSYCL).
DPC++ for example throws the following compiler error:

> clang++ -fsycl -fsycl-targets=nvptx64-nvidia-cuda -Xsycl-target-backend=nvptx64-nvidia-cuda --offload-arch=sm_86 foo.cpp main.cpp
In file included from foo.cpp:3:
In file included from /intel_llvm/build/install/include/sycl/sycl.hpp:16:
In file included from /intel_llvm/build/install/include/sycl/backend.hpp:18:
In file included from /intel_llvm/build/install/include/sycl/detail/backend_traits_opencl.hpp:26:
/intel_llvm/build/install/include/sycl/queue.hpp:1544:31: error: reference to 'queue' is ambiguous
template <> struct hash<sycl::queue> {
                              ^
./foo.hpp:2:9: note: candidate found by name lookup is 'sycl::queue'
  class queue;
        ^
/intel_llvm/build/install/include/sycl/queue.hpp:88:21: note: candidate found by name lookup is 'sycl::_V1::queue'
class __SYCL_EXPORT queue : public detail::OwnerLessBase<queue> {
                    ^
/intel_llvm/build/install/include/sycl/queue.hpp:1545:33: error: reference to 'queue' is ambiguous
  size_t operator()(const sycl::queue &Q) const {
                                ^
./foo.hpp:2:9: note: candidate found by name lookup is 'sycl::queue'
  class queue;
        ^
/intel_llvm/build/install/include/sycl/queue.hpp:88:21: note: candidate found by name lookup is 'sycl::_V1::queue'
class __SYCL_EXPORT queue : public detail::OwnerLessBase<queue> {
                    ^
/intel_llvm/build/install/include/sycl/queue.hpp:1547:9: error: no matching function for call to 'getSyclObjImpl'
        sycl::detail::getSyclObjImpl(Q));
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/intel_llvm/build/install/include/sycl/detail/common.hpp:240:42: note: candidate template ignored: substitution failure [with Obj = sycl::queue]: incomplete type 'sycl::queue' named in nested name specifier
template <class Obj> decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject) {
                              ~~~        ^
foo.cpp:7:22: error: reference to 'queue' is ambiguous
void foo(const sycl::queue& q) {
                     ^
./foo.hpp:2:9: note: candidate found by name lookup is 'sycl::queue'
  class queue;
        ^
/intel_llvm/build/install/include/sycl/properties/queue_properties.hpp:67:7: note: candidate found by name lookup is 'sycl::_V1::queue'
class queue;
      ^
foo.cpp:8:17: error: member access into incomplete type 'const sycl::queue'
  std::cout << q.get_device().template get_info<sycl::info::device::name>() << std::endl;
                ^
./foo.hpp:2:9: note: forward declaration of 'sycl::queue'
  class queue;
        ^
5 errors generated.

For hipSYCL the error looks as follows:

syclcc --hipsycl-targets="cuda:sm_86" foo.cpp main.cpp
syclcc warning: No optimization flag was given, optimizations are disabled by default. Performance may be degraded. Compile with e.g. -O2/-O3 to enable optimizations.
foo.cpp:8:17: error: member access into incomplete type 'const sycl::queue'
  std::cout << q.get_device().template get_info<sycl::info::device::name>() << std::endl;
                ^
./foo.hpp:2:9: note: forward declaration of 'sycl::queue'
  class queue;
        ^
1 error generated when compiling for sm_86.

Therefore, it would be nice to standardize a new header, e.g., called sycl/syclfwd.hpp (like the C++ standard library header iosfwd) which forward declares all possible classes. After a short look into the standard (note: most likely incomplete) that should be possible for the following classes:
sycl/syclfwd.hpp

namespace sycl {
    class platform;
    class context;
    class device;
    class queue;
    class event;
    // ...
}

Advantages:

  • reduce header dependencies
  • possible improve compile times in some scenarios
  • it should not break any existing code since it adds a new header with simple forward declarations

Disadvantages:

  • have to maintain an additional header
  • the forward declared classes may never become template classes

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions