Как я могу использовать std :: make_tuple во время компиляции? - PullRequest
0 голосов
/ 15 февраля 2019

Функция Constexpr, которая возвращает std::array<std:tuple<uint32_t, uint32_t, uint32_t>, size_t>, не работает во время компиляции из-за использования std :: make_tuple.Есть ли способ преодолеть это?

Когда я пытался удалить спецификацию constexpr.Работает правильно.Тем не менее, цель нашего проекта - предоставить такую ​​функцию оценки во время компиляции.

Я получил следующую ошибку:

В вызывающей части:

error: call to non-constexpr function ‘std::tuple<_Elements>& std::tuple<_Elements>::operator=(std::tuple<_Elements>&&) [with _Elements = {unsigned int, unsigned int, unsigned int}]’

В функциональной части:

error: ‘constexpr std::array<std::tuple<unsigned int, unsigned int, unsigned int>, SIZE> GenArrayTuple() [with long unsigned int SIZE = 128]’ called in a constant expression

Код ниже.

template<std::size_t SIZE>
constexpr std::array<std::tuple<uint32_t, uint32_t, uint32_t>, SIZE> 
GenArrayTuple() {
  std::array<std::tuple<uint32_t, uint32_t, uint32_t>, SIZE> array;
  for (uint32_t i = 0; i < SIZE; ++i) {
    // FIXME constexpr
    arr[2*i] = std::make_tuple(i, i * 2, i * 3 + 1);
  }
  return array;
}

constexpr uint32_t n = 128; 
constexpr auto array_tuple = GenArrayTuple<n>();

1 Ответ

0 голосов
/ 15 февраля 2019

На самом деле нет проблем с использованием std::make_tuple в константном выражении в C ++ 14 или более поздних версиях, поскольку C ++ 14 изменил его на constexpr.Таким образом, это допустимое константное выражение, если любые конструкторы классов, используемые для инициализации элементов кортежа, оцениваются как допустимые константные выражения (и таких конструкторов нет, если все типы элементов являются скалярами, такими как std::uint32_t).

Но лучше взгляните на сообщение об ошибке.Функция, на которую он жалуется, это (извлечение некоторых деталей) tuple& tuple::operator=(tuple&&).Оказывается, операторы присваивания из std::tuple не помечены constexpr в текущих версиях C ++, что означает, что любое присвоение объекта tuple не является допустимым константным выражением.(cppreference.com отмечает, что они будут помечены constexpr в C ++ 20; это обычно отражает изменения по сравнению с предложением, уже принятым соответствующей рабочей группой C ++.)

Итак, чтобы обойти это, вы 'Вам нужно будет инициализировать array сразу, а не назначать его элементы в цикле.Вероятно, самый простой способ сделать это с помощью std::make_integer_sequence:

#include <tuple>
#include <array>
#include <cstdint>
#include <utility>

template <std::uint32_t ... I>
constexpr std::array<std::tuple<std::uint32_t, std::uint32_t, std::uint32_t>,
                     sizeof...(I)>
GenArrayTuple_helper(std::integer_sequence<std::uint32_t, I...>) {
    return { std::make_tuple(I, I * 2, I * 3 + 1) ... };
}

template <std::size_t SIZE>
constexpr std::array<std::tuple<std::uint32_t, std::uint32_t, std::uint32_t>,
                     SIZE> 
GenArrayTuple() {
    return GenArrayTuple_helper(std::make_integer_sequence<std::uint32_t, SIZE>{});
}
...