How to stop member function returning T& being defined for T = void (and is supposed to be)
22:37 29 Mar 2026

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  
#include  

template 
struct TestPointerLike{
    T* m_data; 
    [[nodiscard]]
     T& operator[](std::integral auto i) const noexcept requires (!std::same_as, void>) {
        return m_data[i];
    }
};

int main() {
    TestPointerLike test; 
}

: In instantiation of 'struct TestPointerLike':
:14:27:   required from here
   14 |     TestPointerLike test;
      |                           ^~~~
:8:9: error: forming reference to void
    8 |      T& operator[](std::integral auto i) const noexcept requires (!std::same_as, 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  
#include  

template 
struct TestPointerLike{
    T* m_data; 
    [[nodiscard]]
     T& operator[](std::integral auto i) const noexcept requires (!std::same_as, void>);
};

template 
T& TestPointerLike::operator[](std::integral auto i) const noexcept
requires (!std::same_as, void>){
    return m_data[i]; 
}

int main() {
    TestPointerLike test; 
}
: In instantiation of 'struct TestPointerLike':
:18:27:   required from here
   18 |     TestPointerLike test;
      |                           ^~~~
:8:9: error: forming reference to void
    8 |      T& operator[](std::integral auto i) const noexcept requires (!std::same_as, 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  
#include  

template 
struct TestPointerLike{
    T* m_data; 

    template 
     requires(!std::same_as, void> && std::same_as)
    [[nodiscard]]
     U& operator[](std::integral auto i) const noexcept{
        return m_data[i]; 
    }
};



int main() {
    TestPointerLike 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?

c++ c++20 sfinae c++-concepts requires-clause