Search code examples
c++g++sfinaeflexible-array-member

Detect that a struct contains a flexible array member


Say that I have a struct like this

struct foo
{
    int n;
    int values[];
};

Is it possible to detect the flexible array member using SFINAE? At least, I can construct a class template that cannot be instantiated with such struct:

template<class T>
struct invalid_with_fam
{
    T x;
    int unused;
};

If I try to create an invalid_with_fam<foo>:

<source>:14:23:   required from here
<source>:11:9: error: flexible array member 'foo::data' not at end of 'struct invalid_with_fam<foo>'
   11 |     int data[];
      |         ^~~~
<source>:5:9: note: next member 'int invalid_with_fam<foo>::unused' declared here
    5 |     int unused;
      |         ^~~~~~
<source>:2:8: note: in the definition of 'struct invalid_with_fam<foo>'
    2 | struct invalid_with_fam

So now I want to use that so I can disable a template for any such struct. Since this is a non-standard feature, I should mention that I target gcc. Notice that I do not ask whether or not flexible array members are possible. I assume they are, but want to disable certain templated functions based on the fact that it contains such arrays. Example:

template<class T>
void do_stuff(T const& x)
{
   //...
   y = x;  // Slicing would occur here!!!
   //...
}

Thus, it should be a compilation error to use do_stuff with T=foo.

For this to work, I assume that there has to be a way to trigger SFINAE on an invalid type. invalid_with_fam<foo> cannot exist, because the data member after will require an undefined memory layout (is unused part of the array or not?). So if SFINAE works to detect that the class template cannot be instantiated it should work.


Solution

  • There are no FAMs in C++. Any support given by the compilers to this non-standard feature is likely to be inconsistent and not integrate well with the rest of C++.

    Having said that, we can pretend that a FAM is normal C++ code and try to detect it using SFINAE.

    Unfortunately it doesn't work, because only errors in so-called "immediate context" are SFINAE-friendly. The standard does not give a definition to the notion of "immediate context", but it is more or less clear (in particular from this note) that innards of a class being instantiated is not it.

    So the answer is no, it is not detectable using SFINAE using a template similar to invalid_with_fam. Perhaps there are other contexts in which a FAM struct cannot be used and which can be embedded into the "immediate context" of the substitution, but I am not aware of any.