c++const-castsycldpc++

is `const_cast`ing away const on a reference worth it to preserve the api


We have the specific case with the GPU programing paradigm sycl as described in this fix request where we want to use read only access from a buffer. Specifically image the use case like:

namespace my_lib {

using buffer_type = sycl::buffer<2>;

void process_image(sycl::queue& queue, const buffer_type& input, buffer_type& output);

}

This is a sensible interface, the queue which is passed to all operations is mutable, the input is const, the output is not. However, due to the fix request mentioned above, internally this will lead to:

void process_image(sycl::queue& queue, const buffer_type& input, buffer_type& output) {
    // ...
    auto input_accessor = input.get_access<sycl::access::read>(cgh);
    // ...
}

Which will inevitably fail to compile with:

src/gpu_lib/process_image.ipp:112:22: error: no matching member function for call to 'get_access'
                    .get_access<sycl::access::mode::read>(cgh);
                    ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/intel/oneapi/compiler/2023.0.0/linux/bin-llvm/../include/sycl/buffer.hpp:489:3: note: candidate function template not viable: 'this' argument has type 'const sycl::buffer<float, 2, sycl::detail::aligned_allocator<float>, void>', but method is not marked const
  get_access(
  ^

So we come to a decision point, we can either have the API (buffer_type& input) as non-const, which is somewhat lying to the user, because it will not be modified. Or, we use const_cast to allow this behaviour:

  sycl::accessor input_acc =
                const_cast<std::remove_cvref_t<decltype(input)>&>(input)
                    .get_access<sycl::access::mode::read>(cgh);

This leads to 2 questons:

  1. Is casting away the constness of this reference safe?
  2. Which is the better option? Is there a definitive answer on this?

Solution

  • Please define safe. It's UB-prone.

    The github topic mentions that implementations may modify the state of the buffer even if it is const.

    I cannot say for the authors, but this seems like a sound reason not to make it const. I dare say, making the function accept the const buffer_type& is lying to the user more, because that's not compatible with buffer_type's API.

    If get_access function should be made const and some buffer_type's members mutable is another story; it is an option to consider if possible.

    But for the sake of just using the API, I would opt for making the reference non-const.