| Summary: | CDT fails to remove overload from overload set due to substitution error | ||
|---|---|---|---|
| Product: | [Tools] CDT | Reporter: | Nathan Ridge <zeratul976> |
| Component: | cdt-parser | Assignee: | Markus Schorn <mschorn.eclipse> |
| Status: | RESOLVED FIXED | QA Contact: | Markus Schorn <mschorn.eclipse> |
| Severity: | normal | ||
| Priority: | P3 | CC: | cdtdoug |
| Version: | 8.0.1 | ||
| Target Milestone: | 8.0.2 | ||
| Hardware: | All | ||
| OS: | All | ||
| Whiteboard: | |||
Thanks, added testcase and fix. OK, the test case above now works, but something slightly more complicated still fails:
template <bool, typename _Tp = void>
struct enable_if
{
};
template <typename _Tp>
struct enable_if<true, _Tp>
{
typedef _Tp type;
};
template <typename T, typename Signature>
struct has_foo
{
template <typename U, U> struct type_check;
template <typename X> static char (& chk(type_check<Signature, &X::foo> *))[1];
template <typename > static char (& chk(...))[2];
static bool const value = sizeof(chk<T>(0)) == 1;
};
template <typename T>
bool bar(T);
template <typename T>
bool bar(T, typename enable_if<has_foo<T, void(T::*)()>::value>::type* = 0);
int main()
{
bar(0); // ERROR HERE: 'bar' is ambiguous
}
Here, has_foo<int, void(T::*)()>::value evaluates to false, and enable_if<false> does not have a nested 'type' member, so the substitution of 'int' into the second overload causes a substitution error, and so the second overload should be removed from the overload set.
Simplified testcase:
template <bool, typename _Tp = void>
struct enable_if
{
};
template <typename _Tp>
struct enable_if<true, _Tp>
{
typedef _Tp type;
};
template <typename T>
struct has_foo
{
static bool const value = false;
};
template <typename T>
bool bar(T);
template <typename T>
bool bar(T, typename enable_if<has_foo<T>::value>::type* = 0);
int main()
{
bar();
}
Sorry, please ignore the "simplified testcase" in the previous comment, it is wrong. Please also ignore my description of why the substitution failure occurs in comment #2, that was incorrect too :( Here is a correct, and much more simplified, testcase: template <typename T> bool bar(T); template <typename T> bool bar(T, void(T::*)() = 0); int main() { bar(0); // ERROR HERE: 'bar' is ambiguous } Here, the substitution failure occurs because 'void(T::*)()' is ill-formed when T = int. Thanks for the example! This is actually a different bug, for which it is usually better to open a new bug report. Added further testcase and fix. |
In the following code: template <typename T> void foo(T); template <typename T> void foo(T, typename T::type* = 0); int main() { foo(0); // ERROR HERE } the substitution of 'int' into the second overload causes a substitution error (because int::type is not well-formed) and should remove the candidate from the overload set. The call should therefore resolve unambiguously to the first overload. However, CDT gives the following error at the call site: 'foo' is ambiguous ' Candidates are: void foo(int, #0::type *) void foo(int) ' suggesting that it does not remove the second overload from the overload set.