Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

disable template member function if return type is an array

https://www.godbolt.org/z/_4aqsF:

template <typename T> struct Container
{
    template <typename TPred> T find_if(TPred pred);  // the culprit
};

template <typename T> Container<T> MakeContainer(T const &)
{
    return Container<T>();    
}

int main()
{
    auto x = MakeContainer("Hello!");
}

gcc, clang and msvc apparently agree that this cannot compile because find_if would return an array.

(I would have assumed that the member template isn't instantiated since it doesn't get used - apparently, this simplistic view is wrong.)

Why does SFINAE not apply here?

Is there a way to exclude the member template for types where T is not a returnable type?

like image 305
peterchen Avatar asked Nov 26 '18 16:11

peterchen


1 Answers

SFINAE is not in play because the members of the types produced in your MakeContainer return point are not examined during SFINAE of MakeContainer overloads.

SFINAE happens only in an immediate context. Bodies of types and functions are not in-scope and do not cause a subsitution failure.

template <typename T=char[7]> Container<char[7]> MakeContainer(char const (&)[7])

this signature is fine.

Once selected, the Container<char[7]> is instantiated and its methods parsed.

template <typename TPred> char[7] find_if(TPred pred);  // the culprit

there is no TPred that could cause this find_if to be a valid method, so your program is ill formed no diagnostic required.

The correct fix is:

template <typename T> struct Container
{
  template <typename TPred> T find_if(TPred pred);  // the culprit
};
template <class T, std::size_t N> struct Container<T[N]>:
  Container<std::array<T,N>>
{
  using Container<std::array<T,N>>::Container;
};

of course, Container<std::array<T,N>> itself needs a very special find_if and probably constructors. But at least it doesn't break immediately.

like image 106
Yakk - Adam Nevraumont Avatar answered Oct 14 '22 17:10

Yakk - Adam Nevraumont