Re: boost::enable_if. why doesn't it compile?
On 3 Sep., 16:27, Michal <rabbi...@tenbit.pl> wrote:
Do You know why the following program does not compile, ie. why compiler
g++ (GCC) 4.3.0 20080428 (Red Hat 4.3.0-8) cannot deduct that print()
can be invoked on int?
best regards,
Michal
#include <boost/type_traits.hpp>
#include <boost/utility.hpp>
#include <iostream>
#include <typeinfo>
using namespace std;
template<typename T>
void print(typename boost::enable_if_c<boost::is_integral<T>::value,
T>::type &t)
{
cout << "new way. " << typeid(t).name() << " value: " << t << endl;
}
int main(int argc, char *argv[])
{
// just to check if I typed it ok.
cout << typeid(boost::enable_if_c<boost::is_integral<int>::value,
int>::type).name() << endl;
int a=10;
print(a);
return 0 ;
}
error from compiler:
p24.cpp: In function "int main(int, char**)":
p24.cpp:20: error: no matching function for call to "print(int&)"
The problem becomes more easily understandable,
if we get rid of all the additional paraphernalia
of boost::enable_if. You would get a similar problem,
if you would tried a simpler program with the same
fundamental defect:
template<class T>
struct E {
typedef T type;
};
template<typename T>
void print(typename E<T>::type&){}
int main() {
int a;
print(a);
}
The problem here (and in you sfinae experiment) is
that the template parameter T cannot be deduced,
because the single function parameter is in a non-
deduced context. This is so, because the compiler
cannot backtrack in general from the type of
typename E<T>::type the "value" of T. To make
this problem a bit clearer, we add an additional
specialization of template E:
template<class T>
struct E {
typedef T type;
};
template<>
struct E<bool> {
typedef int type;
};
template<typename T>
void print(typename E<T>::type&){}
int main() {
int a;
print(a);
}
Obviously there is no unique way
from E<T>::type to T and for this
reason the standard considers this
situation as "non-deducable context".
Sometimes such a non-deducable context
is what we want (e.g. in the definition
of std::forward), but your sfinae example
doesn't belong to this family. To fix
your program, there are two canonical
solutions.
1) Change the signature of print to
template<typename T>
typename boost::enable_if_c<boost::is_integral<T
::value, void>::type
print(T &t);
T is now just in a deducable context of function
parameter t. In this situation this is probably
the best way to realize that.
2) Change the signature of print to
template<typename T>
void
print(T &t, typename boost::enable_if_c<boost::is_integral<T
::value, void*>::type = 0);
This also works, because T can be deduced from the
first function argument. The second is our dummy
necessary for sfinae. This idiom is necessary for
sfinae on constructors.
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]