Why is_integral_v<string> is true?

Viewed 841

I guess the title of the question does not make much of a sense, but I hope the problem description will spread the light.
Can someone please explain how on earth this is passing the compilation?

template<typename Cont, typename = std::enable_if<std::is_integral_v<std::string>>>
void print(const Cont& cont) 
{
    for (const auto it : cont) {
        cout << it << " ";
    }
    cout << endl;
}

int main()
{
    std::vector<string> V;
    print(V);
}

The original version was:
template<typename Cont, typename = std::enable_if<std::is_integral_v<typename Cont::value_type>>>
I just explicitly put std::string to be sure.

I guess the enable_if should forbid this function to be instantiated at all right??
What am I missing here?

1 Answers

std::enable_if<false> still exists as a type, and that's what you've deduced your unused type parameter to be.

It just exists as a type which does not itself have a nested public member typedef type. That's why you have to use std::enable_if<EXPR>::type or std::enable_if_t<EXPR> to get the behaviour you expect.

You can see examples of exactly your use case in the documentation.


Just for completeness:

Why is_integral_v is true?

It isn't! You just weren't checking what you thought you were.

In future, when you get stuck on something like this (and it can be really hard to see what's wrong when you know what you meant to write), try finding another way to test your assumption. You could just print is_integral_v<std::string> and see if it's really true or false.

Or, of course, get someone else to look at it. Other people can often see right away mistakes that our brain helpfully filters out.

Related