Search code examples
c++constexprcompile-time-type-checking

Detect if T is a reference member at compile time


I'm trying to detect if an argument is a reference member, at compile time. It does not catch it and I can't figure it why.

#include <type_traits>

struct a {
 a(): i1(42), i2(i1){}
 int  i1;
 int& i2;
};

template <typename T>
void Field(T &field) {

    if constexpr (std::is_pointer_v<T>) {
        //handle pointer
    } else if constexpr (std::is_reference_v<T>) {
        static_assert(!std::is_reference_v<T>, "Reference not supported");
    } else {
        //handle value
    }
}


int main()
{
    a a_;

    Field(a_.i2); // I want this to fail at compile time, but it's not
}

What am I doing wrong?


Solution

  • std::is_reference_v works in principle, but not the way you're using it. You have a function template Field(T &field), where the template type parameter T is not going to be deduced to a reference.

    a a_;
    Field(a_.i2); // calls Field<T>(T&) with [T = int]
                  // std::is_reference_v<int> is false
    

    Whatever, you're trying to do here, you could:

    • not work with references directly, but use std::reference_wrapper and always accept a value parameter T field
    • disable deduction by having a std::type_identity_t<T> field parameter, which forces the user to call Field<int&>(a_.i2) manually
      • this could possibly happen through a macro which expands to Field<decltype(a_.i2)>(a_.i2)