Ошибка компилятора с sfinae и пользовательской функцией питания - PullRequest
2 голосов
/ 03 мая 2020

Я хочу реализовать целочисленное значение метапрограммирования с помощью sfinae, например

#include <iostream>

template<bool B, typename T = void> struct enable_if;

template<typename T>
struct enable_if<true, T> { using type = T; };

template<typename T>
struct enable_if<false, T> {};

template<int N, typename T>
typename enable_if <(N == 0), T>::type my_pow(T x) {
    return 1;
};

template<int N, typename T> // block1
typename enable_if <(N > 0) && (N % 2 == 1), T>::type my_pow(T x) {
    return my_pow<N - 1>(x) * x;
};

template<int N, typename T> // block2
typename enable_if <(N > 0) && (N % 2 == 0), T>::type my_pow(T x) {
    T p = my_pow<N / 2>(x);
    return p * p;
};

};

auto y_2_5 = my_pow<2>(5);
//auto y_3_5 = my_pow<3>(5);

int main()
{
    std::cout << y_2_5 << std::endl;
//    std::cout << y_3_5 << std::endl;
}

Это работает для y_2_5, но не работает, если раскомментировать строки с y_3_5. Но если вы поменяете block1 и block2, y_2_5 тоже не будет работать. Возможно, это происходит из-за флага какого-то компилятора. Есть ли возможность это исправить?

1 Ответ

3 голосов
/ 03 мая 2020

Порядок объявлений имеет значение. Какой бы блок ни появился первым, он не увидит другой блок. Это означает, что когда вы делаете разрешение перегрузки в теле первого блока, второй блок не будет кандидатом. Только объявления, которые видны до этого момента, являются кандидатами (исключая другие детали, такие как ADL, которые здесь не применяются).

Средство исправления довольно простое, добавьте объявления обоих шаблонов функций перед их определением. Таким образом, не имеет значения, что на самом деле определено первым.

template<int N, typename T>
typename enable_if <(N > 0) && (N % 2 == 1), T>::type my_pow(T x);

template<int N, typename T>
typename enable_if <(N > 0) && (N % 2 == 0), T>::type my_pow(T x);

template<int N, typename T> // block1
typename enable_if <(N > 0) && (N % 2 == 1), T>::type my_pow(T x) {
    return my_pow<N - 1>(x) * x;
}

template<int N, typename T> // block2
typename enable_if <(N > 0) && (N % 2 == 0), T>::type my_pow(T x) {
    T p = my_pow<N / 2>(x);
    return p * p;
}
...