Я написал свою попытку C ++ 03-совместимой реализации 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;
};
Когда я проверю это в GCC (-std=c++03
), это возвращает 0
потому что конструктор невидим:
class Test { Test(); };
int main()
{
return is_default_constructible<Test>::value;
}
Когда я тестирую его в Visual C ++ (разные версии имеют одинаковое поведение), я получаю обратно 1
,
И когда я проверяю это в Clang (также -std=c++03
), Я получил:
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;
Какой компилятор правильный и почему?
Код не является допустимым C ++ 03, хотя он действителен C ++ 11. Компилятор g ++ 4.8 соблюдает правила C ++ 11 и игнорирует недоступные члены в контексте SFINAE, в то время как компиляторы clang соблюдают C ++ 03, где элемент (конструктор в данном случае) найден и выбран, но проверяется доступ сделать код недействительным. VS (какую бы версию вы не использовали) не соответствует правилам C ++ 11 или C ++ 03, похоже, он игнорирует спецификатор доступа внутри sizeof
полностью.