Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to use concepts to disable member functions that would produce a reference to void?

I would expect it to be possible to write a class like this

template <class T>
struct A {
    T& operator*() 
        requires (!std::is_void_v<T>)
    {
        return *ptr;
    }
    T* ptr;
};

But if I write

A<void> a;

I get the compiler error

prog.cc: In instantiation of 'struct A<void>':
prog.cc:16:13:   required from here
prog.cc:5:8: error: forming reference to void
    5 |     T& operator*()
      |        ^~~~~~~~

even though the requires clause disables that function.

Is there any way to write the class so that the disabled method is acceptable by the compiler?

(I'm aware I could partially specialize A for void but that's less convenient).

like image 914
Ryan Burn Avatar asked Jul 05 '21 22:07

Ryan Burn


1 Answers

No, it is unfortunately not possible. I wish what you wrote actually worked, and it would be the correct way to write it if there was one, but you just can't do it.

Your options are:

template <class T>
struct A {
    // #1: a type trait that handles void for you
    std::add_lvalue_reference_t<T> operator*() requires (!std::is_void_v<T>);

    // #2: make it a template (with only one valid instantiation)
    template <std::same_as<T> U=T>
        requires (!std::is_void_v<U>)
    U& operator*();

    // #3: use auto, even though we know the type and it's easy to spell
    auto& operator*() requires (!std::is_void_v<T>);
};

I dislike all three of them. Your mileage may vary.

like image 91
Barry Avatar answered Oct 22 '22 08:10

Barry