Unexpected overload resolution under SFINAE conditions
Just recently I stumbled across an astonishing effect that
occurred during overload selection of free function templates
under SFINAE conditions.
Let me introduce my demonstration with a common include
header, lets say "Common.h":
// Common.h ---------------------------------------------------------
#include <iostream>
#include <ostream>
template <bool Enable, typename T = void>
struct enable_if { typedef T type; };
template <typename T>
struct enable_if<false, T> {};
template <typename T1, typename T2>
struct is_same { static const bool value = false; };
template <typename T>
struct is_same<T, T> { static const bool value = true; };
template <typename T>
struct Something{};
struct Other{};
// Common.h ---------------------------------------------------------
The first experiment was a simple, non-SFINAE overload
deduction program #1:
// #1 ---------------------------------------------------------
#include "Common.h"
template <class T>
void foo(Something<T>&){ std::cout << "1" << std::endl; }
template <class T>
void foo(T&) { std::cout << "2" << std::endl; }
int main() {
Something<int> x;
foo(x);
}
// #1 ---------------------------------------------------------
I think that every-one expects the same here and all
compiler's I tested (Comeau Online, VS2005-SP1,
mingw (gcc 3.4)) agreed that a single best viable
function can be found and that this one is printing "1".
Now this program was slightly modified to "split" the
general handler ("2") into two handlers using SFINAE:
// #2 ---------------------------------------------------------
#include "Common.h"
template <class T>
void foo(Something<T>&){ std::cout << "1" << std::endl; }
template <class T>
typename enable_if<is_same<T, Other>::value>::type
foo(T&) { std::cout << "2a" << std::endl; }
template <class T>
typename enable_if<!is_same<T, Other>::value>::type
foo(T&) { std::cout << "2b" << std::endl;}
int main() {
Something<int> x;
foo(x);
}
// #2 ---------------------------------------------------------
Even this program compiled and gave one result ("1" again)
- except for Comeau (I tested all available online versions as
well as two versions used in our company - from here I cannot
say which versions) which choked on an *ambiguity*:
"error: more than one instance of overloaded function "foo"
matches the argument list, the choices that match are:
function template "void foo(Something<T> &)"
function template "enable_if<<expression>, void>::type
foo(T &)"
The argument types that you used are: (Something<int>)
foo(x);
^
My question is: Can Comeau be right here? I studied large parts
of 13.3/2-4, 13.3.1.1.1, 13.3.2, 13.3.3.1, 14.8.3, 14.8.2 including
a small promenade into 3.4(2), but could not find any evidence
for this outcome, but maybe my reading/interpretation is wrong.
I would happily appreciate any comments as well as some
references in the standard if a constradictory position is taken!
Thanks and Greetings from Bremen,
Daniel Kr?gler
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]