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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions