Понимание примера SFINAE


Мне трудно понять этот фрагмент кода, который использует SFINAE.

template <typename T>
auto dist() -> typename std::enable_if<std::is_integral<T>::value,
                                       std::uniform_int_distribution<T>>::type;

template <typename T>
auto dist() -> typename std::enable_if<std::is_floating_point<T>::value, 
                                       std::uniform_real_distribution<T>>::type;
...

decltype(dist<float>()) unifDistFloat;
decltype(dist<int>()) unifDistInt;

dist() является именем двух различных прототипов функций, поэтому нет тела, содержащего оператор return. Это означает, что он никогда не возвращает значение типа uniform_real_distribution<T> или uniform_int_distribution<T>.

Так не должно ли decltype потерпеть неудачу при попытке вызвать неполную функцию? Или decltype просто не вызывает функцию вообще, а вместо этого просто вычисляет возвращаемый тип?

2 2

2 ответа:

decltype является недооцененным контекстом. Он просто работает на уровне типа, поэтому достаточно знать, что тело dist, где бы оно ни находилось, возвращает некоторый тип X.

decltype спецификатор проверяет объявленный тип сущности или запрашивает возвращаемый тип выражения, вот что он делает.

Здесь альтернативное использование. для того, чтобы показать, что decltype заботится только о типе любого проходящего выражения

template<typename U >
static typename std::enable_if<std::is_same<U, int>::value, std::uniform_int_distribution <U>>::type
dist(); // NOTE: no function body

template<typename U >
static typename std::enable_if<std::is_same<U, double>::value, std::uniform_real_distribution <U>>::type
dist() 
{
    //return; // NOTE: no return 
}
decltype(dist<T>()) mUniformDistribution;

Вероятно, вопрос, почему компилятор жалуется на функцию dist () как на неполную? я понятия не имею, почему это так.

Демонстрационный пример

template<typename T >
class Random 
{
public:
    Random(const T& min, const T& max)
        : mUniformDistribution(min, max)
    {}

    T operator()()
    {
        return mUniformDistribution(mEngine);
    }

private:
    std::default_random_engine mEngine{ std::random_device()() };

    template<typename U >
    static typename std::enable_if<std::is_same<U, int>::value, std::uniform_int_distribution <U>>::type
    dist(); // NOTE: no function body

    template<typename U >
    static typename std::enable_if<std::is_same<U, double>::value, std::uniform_real_distribution <U>>::type
    dist() 
    {
        //return; // NOTE: no return 
    }
    decltype(dist<T>()) mUniformDistribution;
};

int main()
{
    Random<int> getRandom(0, 9);
    for (int i = 0; i<9; ++i)
        std::cout << getRandom() << '\n';
}