I've written my attempt at a C++03-compatible implementation of is_default_constructible
:
template<class = void> struct is_default_constructible;
template<> struct is_default_constructible<>
{
protected:
// Put base typedefs here to avoid pollution
struct twoc { char a, b; };
template<bool> struct test { typedef char type; };
template<class T> static T declval();
};
template<> struct is_default_constructible<>::test<true> { typedef twoc type; };
template<class T> struct is_default_constructible : is_default_constructible<>
{
private:
template<class U> static typename test<!!sizeof(::new U())>::type sfinae(U*);
template<class U> static char sfinae(...);
public:
static bool const value = sizeof(sfinae<T>(0)) > 1;
};
When I test it in GCC (-std=c++03
), it returns 0
because the constructor is invisible:
class Test { Test(); };
int main()
{
return is_default_constructible<Test>::value;
}
When I test it in Visual C++ (different versions all have the same behavior), I get back 1
.
And when I test it in Clang (also -std=c++03
), I get:
error: calling a private constructor of class 'Test'
template<class U> static typename test<!!sizeof(::new U())>::type sfinae(U *);
^
note: while substituting explicitly-specified template arguments into function template 'sfinae'
static bool const value = sizeof(sfinae<T>(0)) > 1;
^
note: in instantiation of template class 'is_default_constructible<Test>' requested here
return is_default_constructible<Test>::value;
^
error: calling a private constructor of class 'Test'
template<class U> static typename test<!!sizeof(::new U())>::type sfinae(U *);
^
note: while substituting deduced template arguments into function template 'sfinae' [with U = Test]
static bool const value = sizeof(sfinae<T>(0)) > 1;
^
note: in instantiation of template class 'is_default_constructible<Test>' requested here
return is_default_constructible<Test>::value;
Which compiler is correct and why?
The code is not valid C++03, although it is valid C++11. The g++ 4.8 compiler is abiding to the C++11 rules and ignoring inaccessible members in an SFINAE context, while clang compilers is abiding to the C++03 where the member (constructor in this case) is found and selected, but access checks make the code invalid. VS (whatever version you are using) is not abiding to C++11 or C++03 rules, it seems to be ignoring the access specifier inside the sizeof
completely.