Почему я не могу использовать std :: tuple в лямбда-функции constexpr - PullRequest
1 голос
/ 05 февраля 2020

У меня есть следующий код:

#include <string_view>
#include <array>
#include <tuple>

struct Variable
{
  size_t index;
  std::string_view name;
  std::tuple<float, float> bounds;
};

constexpr std::array<Variable, 3> myarray = [](){
    std::array<Variable, 3> res{};
    std::array<std::string_view, 3> strings = {"myvar1", "myvar2", "myvar3"};
    std::array<std::tuple<float, float>, 3> bounds = {{{0,1}, {1,2}, {2,3}}};

    for (std::size_t i = 0; i != res.size(); ++i) {
        res[i] = {i, strings[i], bounds[i]};
    }
    return res;
}();

, но этот код не компилируется из-за std::tuple. По какой причине я не могу использовать std::tuple внутри лямбда-функции?

Я использую

c++ -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -o main.o -c main.cpp

для компиляции кода.

Версия Компилятор: gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)

Я получаю ошибку:

../main.cpp:53:3: error: call to non-constexpr function ‘<lambda()>’
 }();
   ^
../main.cpp:44:51: note: ‘<lambda()>’ is not usable as a constexpr function because:
 constexpr std::array<Variable, num_vars> xrt = [](){
                                               ^
../main.cpp:51:39: error: call to non-constexpr function ‘Variable& Variable::operator=(Variable&&)’
     res[i] = {i, strings[i], bounds[i]};
                                   ^
../main.cpp:16:8: note: ‘Variable& Variable::operator=(Variable&&)’ is not usable as a constexpr function because:
 struct Variable
        ^~~~~~~~

Ответы [ 3 ]

3 голосов
/ 05 февраля 2020

Ни tuple, ни pair не имеют присваивания constexpr в C ++ 17.

Но даже тривиальная структура, содержащая пару значений, сделает эту работу. При необходимости вы можете реализовать собственную совместимую с constexpr структуру. Тривиальная версия без пуха вам нужна:

struct Couple {
  float a, b;  
};

struct Variable
{
  size_t index;
  std::string_view name;
  Couple bounds;
};

constexpr std::array<Variable, 3> myarray = [](){
    std::array<Variable, 3> res{};
    std::array<std::string_view, 3> strings = {"myvar1", "myvar2", "myvar3"};
    std::array<Couple, 3> bounds = {{{0,1}, {1,2}, {2,3}}};

    for (std::size_t i = 0; i != res.size(); ++i) {
        res[i] = {i, strings[i], bounds[i]};
    }
    return res;
}();

Можно расположить код так, как он будет использовать tuple для будущего стандарта

1 голос
/ 05 февраля 2020

std::tuple операторы присваивания не constexpr до c ++ 20. Если вы избегаете операторов присваивания и строите свои кортежи на месте, тогда ваш код компилируется:

constexpr std::array<Variable, 3> myarray = [](){
    std::array<std::string_view, 3> strings = {"myvar1", "myvar2", "myvar3"};
    std::array<std::tuple<float, float>, 3> bounds = {{{0,1}, {1,2}, {2,3}}};

    std::array<Variable, 3> res { {
        {0, strings[0], bounds[0]},
        {1, strings[1], bounds[1]},
        {2, strings[2], bounds[2]}
    } };
    return res;
}();
0 голосов
/ 05 февраля 2020

Поскольку C ++ 14, конструкторы std::tuple имеют значение constexpr (по крайней мере те, которые не принимают распределители), поэтому вы можете использовать один из них вместо оператора присваивания.

Начать добавление constexpr конструктор для вашего класса

struct Variable
{
    size_t index{};
    std::string_view name{};
    std::tuple<float, float> bounds{};

    constexpr Variable(size_t i, std::string_view str)
        : index{i}, name{str}, bounds{i, i + 1} {}
};

Затем вы можете создать массив, используя несколько шаблонных функций, используя преимущества std :: integer_sequence .

template <class Element, std::size_t... I, typename... ArgsType>
constexpr auto make_array_with_indices_impl(std::index_sequence<I...>, ArgsType... args)
{
    return std::array<Element, sizeof...(args)>{
        Element(I, args)...
    };    
}

template <class Element, typename... ArgsType>
constexpr auto make_array_with_indices(ArgsType... args)
{
    return make_array_with_indices_impl<Element>(
        std::index_sequence_for<ArgsType...>{}, args...
    );
}

Здесь пример их использования.

...