3

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.

user877329
  • 6,717
  • 8
  • 46
  • 88
  • *Is it possible to detect the VLA* -- The compiler will do that, since VLA's are not C++. – PaulMcKenzie Jul 06 '22 at 17:03
  • 1
    Since they are not standard C++, you should at least mention for which compiler you are asking. There wouldn't really be a guarantee that they implement it the same way. – user17732522 Jul 06 '22 at 17:04
  • 9
    And that is not a VLA, even in C. It is a _flexible array member_ in C, but they are also non-standard in C++. – user17732522 Jul 06 '22 at 17:04
  • 1
    As mentioned, a compiler vendor could implement that in any way they see fit, and that includes not being able to be detected by "normal means" that you would use for standard C++ constructs. As an example, an older version of g++ did not accept VLA's as an argument to STL functions that took iterators, even though "regular" arrays had no such issue. So there is no guarantee whatsoever that any SFINAE tricks will work. – PaulMcKenzie Jul 06 '22 at 17:10
  • There are approaches to support FAMs in C++ https://thephd.dev/_vendor/future_cxx/papers/d1039.html Current implementation-defined and possibly UB solutions are to use `values[]` as is or `values[0]` or `values[1]` in the struct definition and possibly accessing elements behind the last index. – Sebastian Jul 06 '22 at 17:12
  • Since you are using C++, you should replace the array with `std::vector`. The array is an ancient technology that marks the end of the structure, where another field could begin. There is no guarantee that `values[0]` or `values[1]` will be valid. The compiler is allowed to add padding and other overhead to a structure (such as virtual tables). – Thomas Matthews Jul 06 '22 at 19:33
  • 1
    @ThomasMatthews Unless, the struct is used by a C-only component. – user877329 Jul 06 '22 at 20:01

1 Answers1

2

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.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243