@@ -40,6 +40,8 @@ namespace sycl {
4040inline namespace _V1 {
4141namespace ext ::oneapi::experimental {
4242
43+ template <typename T, typename PropertyListT> class device_global ;
44+
4345namespace detail {
4446// Type-trait for checking if a type defines `operator->`.
4547template <typename T, typename = void >
@@ -49,6 +51,20 @@ struct HasArrowOperator<T,
4951 std::void_t <decltype (std::declval<T>().operator ->())>>
5052 : std::true_type {};
5153
54+ template <typename T, typename PropertyListT, typename >
55+ class device_global_base ;
56+
57+ // Checks that T is a reference to either device_global or
58+ // device_global_base. This is used by the variadic ctor to allow copy ctors to
59+ // take preference.
60+ template <typename T> struct IsDeviceGlobalOrBaseRef : std::false_type {};
61+ template <typename T, typename PropertyListT>
62+ struct IsDeviceGlobalOrBaseRef <device_global_base<T, PropertyListT, void > &>
63+ : std::true_type {};
64+ template <typename T, typename PropertyListT>
65+ struct IsDeviceGlobalOrBaseRef <device_global<T, PropertyListT> &>
66+ : std::true_type {};
67+
5268// Base class for device_global.
5369template <typename T, typename PropertyListT, typename = void >
5470class device_global_base {
@@ -63,14 +79,49 @@ class device_global_base {
6379 pointer_t get_ptr () noexcept { return usmptr; }
6480 pointer_t get_ptr () const noexcept { return usmptr; }
6581
82+ template <typename , typename , typename > friend class device_global_base ;
83+
84+ #ifndef __SYCL_DEVICE_ONLY__
85+ template <typename OtherT, typename OtherProps>
86+ static constexpr const T &
87+ ExtractInitialVal (const device_global_base<OtherT, OtherProps> &Other) {
88+ if constexpr (OtherProps::template has_property<device_image_scope_key>())
89+ return Other.val ;
90+ else
91+ return Other.init_val ;
92+ }
93+ #endif // __SYCL_DEVICE_ONLY__
94+
6695public:
6796#if __cpp_consteval
68- template <typename ... Args>
97+ // The SFINAE is to allow the copy constructors to take priority.
98+ template <
99+ typename ... Args,
100+ std::enable_if_t <
101+ sizeof ...(Args) != 1 ||
102+ (!IsDeviceGlobalOrBaseRef<std::remove_cv_t <Args>>::value && ...),
103+ int > = 0 >
69104 consteval explicit device_global_base (Args &&...args) : init_val{args...} {}
70105#else
71106 device_global_base () = default;
72107#endif // __cpp_consteval
73108
109+ #ifndef __SYCL_DEVICE_ONLY__
110+ template <typename OtherT, typename OtherProps,
111+ typename = std::enable_if_t <std::is_convertible_v<OtherT, T>>>
112+ constexpr device_global_base (
113+ const device_global_base<OtherT, OtherProps> &DGB)
114+ : init_val{ExtractInitialVal (DGB)} {}
115+ constexpr device_global_base (const device_global_base &DGB)
116+ : init_val{DGB.init_val } {}
117+ #else
118+ template <typename OtherT, typename OtherProps,
119+ typename = std::enable_if_t <std::is_convertible_v<OtherT, T>>>
120+ constexpr device_global_base (const device_global_base<OtherT, OtherProps> &) {
121+ }
122+ constexpr device_global_base (const device_global_base &) {}
123+ #endif // __SYCL_DEVICE_ONLY__
124+
74125 template <access::decorated IsDecorated>
75126 multi_ptr<T, access::address_space::global_space, IsDecorated>
76127 get_multi_ptr () noexcept {
@@ -100,14 +151,28 @@ class device_global_base<
100151 T *get_ptr () noexcept { return &val; }
101152 const T *get_ptr () const noexcept { return &val; }
102153
154+ template <typename , typename , typename > friend class device_global_base ;
155+
103156public:
104157#if __cpp_consteval
105- template <typename ... Args>
158+ // The SFINAE is to allow the copy constructors to take priority.
159+ template <
160+ typename ... Args,
161+ std::enable_if_t <
162+ sizeof ...(Args) != 1 ||
163+ (!IsDeviceGlobalOrBaseRef<std::remove_cv_t <Args>>::value && ...),
164+ int > = 0 >
106165 consteval explicit device_global_base (Args &&...args) : val{args...} {}
107166#else
108167 device_global_base () = default;
109168#endif // __cpp_consteval
110169
170+ template <typename OtherT, typename OtherProps,
171+ typename = std::enable_if_t <std::is_convertible_v<OtherT, T>>>
172+ constexpr device_global_base (const device_global_base<OtherT, OtherProps> &) =
173+ delete;
174+ constexpr device_global_base (const device_global_base &) = delete;
175+
111176 template <access::decorated IsDecorated>
112177 multi_ptr<T, access::address_space::global_space, IsDecorated>
113178 get_multi_ptr () noexcept {
@@ -124,6 +189,7 @@ class device_global_base<
124189 const T>(this ->get_ptr ());
125190 }
126191};
192+
127193} // namespace detail
128194
129195template <typename T, typename PropertyListT = empty_properties_t >
@@ -151,6 +217,7 @@ class
151217 : public detail::device_global_base<T, detail::properties_t <Props...>> {
152218
153219 using property_list_t = detail::properties_t <Props...>;
220+ using base_t = detail::device_global_base<T, property_list_t >;
154221
155222public:
156223 using element_type = std::remove_extent_t <T>;
@@ -167,10 +234,11 @@ class
167234 " Property list is invalid." );
168235
169236 // Inherit the base class' constructors
170- using detail::device_global_base<
171- T, detail::properties_t <Props...>>::device_global_base;
237+ using detail::device_global_base<T, property_list_t >::device_global_base;
238+
239+ constexpr device_global (const device_global &DG)
240+ : base_t (static_cast <const base_t &>(DG)) {}
172241
173- device_global (const device_global &) = delete ;
174242 device_global (const device_global &&) = delete ;
175243 device_global &operator =(const device_global &) = delete ;
176244 device_global &operator =(const device_global &&) = delete ;
0 commit comments