2016-10-30 12 views
3

Я пытаюсь обернуть голову вокруг SFINAE. Мы используем его, чтобы проверить, есть ли у класса метод «Пассажиры».Проверка SFINAE C++

С некоторыми онлайн-примерами мы построили следующие классы шаблонов.

#ifndef TYPECHECK 
#define TYPECHECK 

#include "../Engine/carriage.h" 

namespace TSS{ 

template<typename T> 
class has_passengers{ 
private: 
    typedef char one; 
    typedef struct{char a[2];} two; 

    template<typename C> static one test(decltype(&C::Passengers)); 
    template<typename C> static two test(...); 
public: 
    static bool const value = sizeof(test<T>(0)) == sizeof(one); 
}; 

template<typename T> 
struct CarriageTypeCheck{ 
    static_assert(has_passengers<T>::value, "Train initialized with illegal carriage"); 
}; 

} 


#endif // TYPECHECK 

я часть, как выбирается либо из двух тест-методов, но то, что я не понимаю, почему test<T> инициализируется 0 в следующей строке:

static bool const value = sizeof(test<T>(0)) == sizeof(one); 

я могу не видите, как 0 важно для проверки работы. Другое дело - почему используется decltype?

+0

Вы не проверяете, имеет ли класс функцию-член 'Пассажиры'. Вы проверяете, есть ли у него член «Пассажиры», который может быть функцией, но не обязательно. – krzaq

+0

Хорошая точка! Благодаря! –

ответ

2

Первая перегруженная функция (потенциально) принимает указатель на метод класса в качестве параметра. Из-за наследия C++ от C значение 0 преобразуется в указатель NULL, или nullptr. Итак, если SFINAE не выдает первую перегруженную функцию, test<T>(0) становится действительным вызовом функции, а его sizeof равен sizeof(one). В противном случае это разрешит второй перегруженный вызов функции.

И короткий ответ о том, почему используется decltype: иначе это недействительно C++. В объявлении функции параметр функции должен быть типами, определяющими типы параметров для функции. &C::Passengers не является типом (в контексте его предполагаемого использования), поэтому это недействительно C++. decltype(), который автоматически получает тип своего аргумента, делая его действительным C++.

+0

Хорошо. Но разве это не будет равно «размеру (два)», если у T нет Пассажиров? Тогда вызов будет тестироваться (nullpointer), и тогда размер будет равен 2? –

+0

@BenjaminLarsen Если T не имеет Пассажиров, тип дедукции не удался, шаблон функции будет проигнорирован; так работает SFINAE. Нет такого правила, чтобы передать нулевой указатель для этого случая, без SFINAE, вы получите ошибку complie. – songyuanyao

+0

Я думаю, что получил это сейчас! Спасибо вам, ребята. –

1

Я не вижу, как 0 важно для проверки работы.

Поскольку 0 можно было бы использовать в качестве аргумента для обоих случаев (то есть две перегружена test); для указателя-члена (рассматривается как нулевой указатель) и вариационных аргументов ....

Другое дело - почему используется термин decltype?

decltype используется для описания типа указателя члена (т.е. &C::Passengers) в качестве параметра test.