Генерация кода шаблона C ++ Ошибка: использование 'some_variable' перед удержанием 'auto' - PullRequest
2 голосов
/ 08 мая 2019

Я столкнулся с некоторыми проблемами с этим конкретным кодом.Скорее всего, проблема связана с указателем на член типа Harry, хранящимся в кортеже , и vector с переменной типа Harry, посколькувсе другие более простые варианты работают.

Ошибка, которую я получаю с g ++:


main.cpp: In instantiation of 'abra(const std::vector<A>&, const std::tuple<_Elements ...>&) [with A = Harry; B = {int Harry::*, int* Harry::*}]::<lambda(const auto:1&)> [with auto:1 = int Harry::*]':

main.cpp:10:13:   required from 'void tuple_foreach_constexpr(const std::tuple<T ...>&, F) [with long unsigned int i = 0; long unsigned int size = 2; F = abra(const std::vector<A>&, const std::tuple<_Elements ...>&) [with A = Harry; B = {int Harry::*, int* Harry::*}]::<lambda(const auto:1&)>; T = {int Harry::*, int* Harry::*}]'

main.cpp:17:82:   required from 'void tuple_foreach_constexpr(const std::tuple<_Elements ...>&, F) [with F = abra(const std::vector<A>&, const std::tuple<_Elements ...>&) [with A = Harry; B = {int Harry::*, int* Harry::*}]::<lambda(const auto:1&)>; T = {int Harry::*, int* Harry::*}]'

main.cpp:29:32:   required from 'void abra(const std::vector<A>&, const std::tuple<_Elements ...>&) [with A = Harry; B = {int Harry::*, int* Harry::*}]'

main.cpp:56:27:   required from here

main.cpp:31:82: error: use of 'a' before deduction of 'auto'

             if constexpr(std::is_pointer<typename std::remove_reference<decltype(a.*x)>::type>::value)

                                                                                  ^

main.cpp:33:30: error: invalid type argument of unary '*' (have 'int')

                 std::cout << *(a.*x) << std::endl;

                              ^~~~~~~

main.cpp:6:6: error: 'void tuple_foreach_constexpr(const std::tuple<T ...>&, F) [with long unsigned int i = 1; long unsigned int size = 2; F = abra(const std::vector<A>&, const std::tuple<_Elements ...>&) [with A = Harry; B = {int Harry::*, int* Harry::*}]::<lambda(const auto:1&)>; T = {int Harry::*, int* Harry::*}]', declared using local type 'abra(const std::vector<A>&, const std::tuple<_Elements ...>&) [with A = Harry; B = {int Harry::*, int* Harry::*}]::<lambda(const auto:1&)>', is used but never defined [-fpermissive]

 void tuple_foreach_constexpr(const std::tuple<T...>& tuple, F func)

      ^~~~~~~~~~~~~~~~~~~~~~~

код:

#include <iostream>
#include <tuple>
#include <vector>

template<size_t i, size_t size, typename F, typename... T>
void tuple_foreach_constexpr(const std::tuple<T...>& tuple, F func)
{
    if constexpr(i<size)
    {
        func(std::get<i>(tuple));
        tuple_foreach_constexpr<i+1, size, F, T...>(tuple, func);
    }
}
template<typename F, typename... T>
void tuple_foreach_constexpr(const std::tuple<T...>& tuple, F func)
{
    tuple_foreach_constexpr<0, std::tuple_size<std::tuple<T...>>::value, F, T...>(tuple, func);
}

template<typename A, typename... B>
void abra
(
    const std::vector<A>& a_vector,
    const std::tuple<B...>& b_tuple
)
{
    for(const auto& a : a_vector)
    {
        tuple_foreach_constexpr(b_tuple, [&a](const auto &x)
        {
            if constexpr(std::is_pointer<typename std::remove_reference<decltype(a.*x)>::type>::value)
            {
                std::cout << *(a.*x) << std::endl;
            }
            else
            {
                std::cout << a.*x << std::endl;
            } // this does NOT work

            //std::cout << a.*x << std::endl; // this does work
        });
    }
}

struct Harry
{
    int a;
    int* b;
};    

int main()
{
    int m = 20;
    std::vector<Harry> h_vector = {Harry{10, &m}};
    std::tuple t_tuple = std::make_tuple(&Harry::a, &Harry::b);

    abra(h_vector, t_tuple);
}

Это будетбыло бы неплохо, если бы у кого-то были советы о том, как решить эту проблему.

(Я знаю, что все это выглядит так, как будто нет никакого смысла, зачем кому-то это нужно делать. Однако мой приоритет - не писатьхороший, пригодный для использования код, но для изучения вещей, а также я действительно хочу, чтобы эта архитектура, которую я задумал, работала.)

1 Ответ

2 голосов
/ 08 мая 2019

Было бы очень хорошо, если бы у кого-нибудь были советы, как это решить.

Прежде всего: я воспроизвожу вашу ошибку с помощью g ++, но моя компиляция clang ++ (7.0.1)Ваш код без проблем.

Кто прав?g ++ или clang ++?

Я не адвокат по языку и не уверен, но подозреваю, что это ошибка g ++.

Что говорит g ++?

Это говоритчто в этом цикле

for(const auto& a : a_vector)
{
    tuple_foreach_constexpr(b_tuple, [&a](const auto &x)
    {
        if constexpr(std::is_pointer<typename std::remove_reference<decltype(a.*x)>::type>::value)
        {
            std::cout << *(a.*x) << std::endl;
        }
        else
        {
            std::cout << a.*x << std::endl;
        } // this does NOT work

        //std::cout << a.*x << std::endl; // this does work
    });
}

переменная a, то есть переменная auto (const auto& a : a_vector), поэтому ее тип должен выводиться компилятором, который захватывается внутри лямбда-функции,используется (decltype(a.*x)) перед вычетом типа.

В любом случае, решение проблемы простое: чтобы сделать g ++ счастливым, явное определение.

Вы знаете, что aявляется элементом a_vector, который определяется как std::vector<A> const &, так что вы знаете, что a является A const &.

Итак, если вы пишете цикл

for ( A const & a : a_vector )
 {
   // ....
 }

больше нет необходимости выводить тип a и ваш код компилируется также с помощью g ++.

...