While testing SFINAE, I found something that I don't think should work

爷,独闯天下 提交于 2019-12-11 06:55:50

问题


I found an interesting conditional function exclusion that I got from this site and while testing it I came across this:

#include<type_traits>

namespace detail
{
    enum enabler {};
}

template <int overload, typename Condition>
using EnableIf = std::enable_if_t<Condition::value, detail::enabler>;

template <typename T,
    EnableIf<0, std::is_same<T, int>>...>
    T twice(T t) { return 2 * t; }

template <typename T,
    EnableIf<0, std::is_same<T, float>>...>
    T twice(T t) { return 2 * t; }

int main()
{
    twice(1);
    twice(1.f);
    return 0;
}

Shouldn't this cause a compiler error because the EnableIf type are the same in both functions? I was going to use a different number for each overload and have a template class that would contain the enabler enum so that it would be a different type, but it would seem that it isn't necessary. Is this a defect or am I missing something?

I've tested this on VC++ (2017) and clang.

Although VC++ compiler doesn't complain, apparently the intellisense doesn't like it:

Which is what I thought, but it complains regardless if I use a different integer, or even go to the trouble of doing what I said I was going to do.


回答1:


Shouldn't this cause a compiler error because the EnableIf type are the same in both functions?

But they're not the same. One takes a pack of std::enable_if_t<std::is_same<T, int>::value, detail::enabler> and the other takes a pack of std::enable_if_t<std::is_same<T, float>::value, detail::enabler>. Those are entirely unrelated types, so you are declaring two unrelated function templates. Indeed, at least one of those two types is ill-formed, so they cannot have the same type - at best both are ill-formed.

This is perfectly fine. The different number is not only unnecessary, but also wouldn't do anything - alias templates are transparent, so the number would disappear since you're not using it in the actual type expression.

Only if both EnableIf conditions were viable, then you'd end up with the same type (detail::enabler) in both functions.




回答2:


Looks like I was too quick on the draw and marked Barry's answer as the correct answer. However it would seem that it is not quite right, or at least not clear.

A function can have a valid overload so long as its parameters are different. A template function is the same, but its signature also includes the template parameters. Thus, you can have the same function name with the same parameter list, but with different template parameters, and it will still be considered an overload.

So, if both functions were viable with the same type T, then there would be a collision.

However, since there is a EnableIf that would resolve to a type only under mutually exclusive conditions, then even though the 2nd template type would resolve to the same type detail::enabler, the first template parameter would be a different type (this would still work even if there was no auto deduction based on function parameters, with the same function parameter types). Thus, this would still be a different function overload.

To what @Barry said that std::enable_if_t<std::is_same<T, int>::value, detail::enabler> and std::enable_if_t<std::is_same<T, float>::value, detail::enabler> being entirely unrelated types. He is sort of correct. When valid, they do resolve to exactly the same type, but what he failed to mention was that they are just not ever valid at the same time.



来源:https://stackoverflow.com/questions/42773131/while-testing-sfinae-i-found-something-that-i-dont-think-should-work

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!