Traits classes can be defined to check if a C++ class has a member variable, function or a type (see here).
Curiously, the ConceptTraits do not include traits to che
Warning: some analysis below is obsolete as of C++11. In C++11, access checking is done prior to instantiation and access violation is-not-an-error. Therefore the attached code may be more compliant. I haven't re-analyzed it.
I'm pretty new to SFINAE. Today it occurred to me to put a test expression inside a sizeof
inside a template parameter in a function argument type.
According to N2634 this is not wrong, but highly unportable. (EDIT: appears to be compliant to C++0x FCD.) It can only return positive or fail to compile in GCC 4.2; GCC 4.5 scores a 3 out of 3 for my test cases.
The SFINAE rules were broadened (in this case) since C++03 in the FCD. New §14.8.2/8 (emphasis mine):
If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed if written using the substituted arguments. Access checking is not done as part of the substitution process. Consequently, when deduction succeeds, an access error could still result when the function is instantiated. Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure. [ Note: The evaluation of the substituted types and expressions can result in side effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such side effects are not in the “immediate context” and can result in the program being ill-formed.
template< class T >
class is_default_constructible {
template
class receive_size{};
template< class U >
static int sfinae( receive_size< sizeof U() > * );
template< class U >
static char sfinae( ... );
public:
enum { value = sizeof( sfinae(0) ) == sizeof(int) };
};
class q { q(); };
class r { r(int); };
#include
using namespace std;
int main() {
cerr << is_default_constructible::value << endl // outputs 1
// fails to compile: access violation
// FCD demands that access violations be unrecoverable
// indeed, it's murky: q is default-constructible, but only "rarely"
//<< is_default_constructible::value << endl
<< is_default_constructible::value << endl; // outputs 0
}