How to stop member function returning T& being defined for T = void (and is supposed to be)

16 hours ago 3
ARTICLE AD BOX

I'm trying to create a pointer like type wrapper for CUDA device pointers, but ran into a problem trying to define T& operator[]. By default, the compiler complains that I'm attempting to "form reference from void" So I attempted to use C++20 concepts in order to avoid this. I get the same error (examples all normal C++ code, not cuda, and have the same issues):

#include <type_traits> #include <concepts> template<typename T> struct TestPointerLike{ T* m_data; [[nodiscard]] T& operator[](std::integral auto i) const noexcept requires (!std::same_as<std::remove_cvref_t<T>, void>) { return m_data[i]; } }; int main() { TestPointerLike<void> test; } <source>: In instantiation of 'struct TestPointerLike<void>': <source>:14:27: required from here 14 | TestPointerLike<void> test; | ^~~~ <source>:8:9: error: forming reference to void 8 | T& operator[](std::integral auto i) const noexcept requires (!std::same_as<std::remove_cvref_t<T>, void>) { | ^~~~~~~~ Compiler returned: 1

See godbolt:

https://godbolt.org/z/aarrovhhv

I tried to figure out how to solve this, and I saw this question: requires clause for a non-template member function in a template class

And thought it was complaining about the solution I thought would work but didn't not working. The answer doesn't work. I get the same issue.

#include <type_traits> #include <concepts> template<typename T> struct TestPointerLike{ T* m_data; [[nodiscard]] T& operator[](std::integral auto i) const noexcept requires (!std::same_as<std::remove_cvref_t<T>, void>); }; template <class T> T& TestPointerLike<T>::operator[](std::integral auto i) const noexcept requires (!std::same_as<std::remove_cvref_t<T>, void>){ return m_data[i]; } int main() { TestPointerLike<void> test; } <source>: In instantiation of 'struct TestPointerLike<void>': <source>:18:27: required from here 18 | TestPointerLike<void> test; | ^~~~ <source>:8:9: error: forming reference to void 8 | T& operator[](std::integral auto i) const noexcept requires (!std::same_as<std::remove_cvref_t<T>, void>); | ^~~~~~~~ Compiler returned: 1

See godbolt link: https://godbolt.org/z/jWGeffqEx

And the first actual solution (I realized they posted as a solution, not a problem) didn't work (first godbolt link tests that).

The only thing I've found to actually work is this:

#include <type_traits> #include <concepts> template<typename T> struct TestPointerLike{ T* m_data; template<typename U = T> requires(!std::same_as<std::remove_cvref_t<T>, void> && std::same_as<T, U>) [[nodiscard]] U& operator[](std::integral auto i) const noexcept{ return m_data[i]; } }; int main() { TestPointerLike<void> test; }

see godbolt link https://godbolt.org/z/5YMTYYd43

Is there away to get this to work more or less like I intended it to in the first example?

Read Entire Article