mercredi 14 avril 2021

universal reference cannot bind to packed struct fields in gcc/g++

  • This code compiles fine in clang without any change but in g++ it throws an error about the packed struct field cannot be bound to a reference.
  • Also make_pair(packed_bitfield, packed_bitfield) gives similar compile error.
  • If the code which calls universal reference function f can be altered, I can pass f(static_cast<const int &>(x.i)) or as_const(x.i) to universal reference function.
  • The const creates a temporary which is aligned. But in many cases i cannot change the calling code.

In what cases will my fix fail to work ? Am i missing any corner cases ?

#include<iostream>
using namespace std;

template<typename T> 
int f(T&& args) {
    return args;
}

struct X {
    char c;
    unsigned int i;
} __attribute__((packed));

int main() {
    X x;
    x.i = 3;
    cout <<"x.i= "<<f(x.i)<<endl;
    return 0;
}
test3.cpp: In function ‘int main()’:
test3.cpp:16:22: error: cannot bind packed field ‘x.X::i’ to ‘unsigned int&’
   16 |  cout <<"x.i= "<<f(x.i)<<endl;
      |                    ~~^

To fix this add const T && ref universal ref and another overload template function f(const L& arg) which is only instantiated if L is a non rvalue reference. The new code becomes

template<typename T>
expr_lhs<const T> f(const  T &&  head)
{
        cout <<"in const universal ref ";
        return expr_lhs<const T>(forward<const T>( head )) ;
}

template<typename T,typename enable_if<  !is_rvalue_reference<T>::value   , void >::type* = nullptr >
int f(const T &head){
        cout <<"in const non rvalue ref ";
        return 17;
}

compiles and produces output

  • 5= in const universal ref 5
  • temp rvalue = in const universal ref 0
  • rvalue = in const universal ref 3
  • i = in const non rvalue ref 17
  • x.i= in const non rvalue ref 17

Aucun commentaire:

Enregistrer un commentaire