Массивы указателей на функции в Visual Studio - PullRequest
3 голосов
/ 18 июня 2019

Гийом Рацико дал отличный ответ на этот вопрос о том, как я могу специализировать переменные шаблона. Но у меня возникают проблемы в с созданием шаблонного массива указателей на функции. Этот код например:

struct vec
{
    double x;
    double y;
    double z;
};

namespace details
{
template <typename T>
constexpr double X(const T& param) { return param.x; }

template <typename T>
constexpr double Y(const T& param) { return param.y; }

template <typename T>
constexpr double Z(const T& param) { return param.z; }
}

template <typename T, typename = void>
constexpr double (*my_temp[])(const vec&) = { &details::X<T>, &details::Y<T> };

template <typename T>
constexpr double (*my_temp<T, enable_if_t<is_floating_point_v<decltype(details::X(T()))>>>[])(const vec&) = { &details::X<T>, &details::Y<T>, &details::Z<T> };


int main() {
    vec foo = { 1.0, 2.0, 3.0 };

    for(const auto i : my_temp<decltype(foo)>) {
        cout << (*i)(foo) << endl;
    }
}

В выходах gcc :

1
2
3

Но в выводятся только:

1
2

Есть ли что-то, что я могу сделать, чтобы обойти это?

1 Ответ

1 голос
/ 18 июня 2019

Добро пожаловать в мир ошибок компилятора! Ваш синтаксис полностью действителен, но только GCC может скомпилировать его.

До сих пор я тестировал несколько версий clang, gcc и msvc.

Ваш вариант с необработанным массивом указателей на функции, только GCC анализирует его правильно. Clang 8.0.0 потерпит крах, и MSCV не скомпилирует его.

Я попробовал два других варианта: с псевдонимом шаблона и std::array

Шаблон псевдонима указателя функции :

template<typename T>
using fptr = auto(*)(T const&) -> double;

template <typename T, typename = void>
constexpr fptr<T> my_temp[] = {
    &details::X<T>, &details::Y<T>
};

template <typename T>
constexpr fptr<T> my_temp<T, enable_if_t<is_floating_point_v<decltype(details::X(T()))>>>[] = {
    &details::X<T>, &details::Y<T>, &details::Z<T>
};

std::array + CTAD :

template <typename T, typename = void>
constexpr std::array my_temp = {
    &details::X<T>, &details::Y<T>
};

template <typename T>
constexpr std::array my_temp<T, enable_if_t<is_floating_point<decltype(details::X(T()))>::value>> = {
    &details::X<T>, &details::Y<T>, &details::Z<T>
};

Чтобы удалить CTAD, просто используйте std::array<auto(*)(const vec&) -> double, 3>.

Вот результаты:

+------------+-------+-------+-------+
| Compiling? |  GCC  | Clang | MSVC  |
+------------+-------+-------+-------+
| raw array  |  Yes  |  ICE  |  No   |
+------------+-------+-------+-------+
| fptr alias |  Yes  |  ICE  |  Yes  |
+------------+-------+-------+-------+
| std::array |  Yes  |  Yes  |  Yes  |
+------------+-------+-------+-------+

Обратите внимание, что в следующем гряде 9 он будет на одном уровне с GCC. Для всех версий требуется как минимум MSVC 2017. Обходной путь, я уверен, можно заставить его работать и с msvc 2015.

В конце концов, если это работает на платформе, которая вам нужна прямо сейчас, это будет хорошо. std::array имеют небольшую стоимость времени компиляции, но необработанный массив на данный момент удивительно менее переносим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...