Home > Net >  deducing return type template c
deducing return type template c

Time:12-09

I'm making a parser combinator in c . Currently, I'm trying to make a sequence function that will call other parsers in order and return all the results in a Tuple.

Code

template<typename T>
T parse(std::function<T(Stream*)> parser, Stream* stream)
{
    return parser(stream);
}

std::function<char(Stream*)> Char(char c)
{
    return [=](Stream* stream) -> char {
        auto ch = stream->Next();
        if (ch == c) {
            stream->Consume(1);
            return c;
        }
        return 0;
    };
}


template <typename ...T, typename R>
std::function<R(Stream*)> Seq(T... a)
{
    return [=](Stream* stream) -> R {
        std::tuple tuple = { a(stream)... };
        return tuple;
    };
}


The problem is that the function Seq needs to know the return type which is a Tuple. This tuple is made of all the results of the functions inside the parameter pack. So I don't know how to tell the compiler what the return type is.

This is the main code.

auto& charA = Char('a');
auto& seq = Seq(Char('#'), charA);

Stream stream("text.txt");

parse(seq, &stream);

Here is the error trace.

TestLayer.cpp(338,27): error C3547: el parámetro de plantilla 'R' no se puede usar porque sigue a un paquete de parámetros de plantilla y no se puede deducir de los parámetros de funciones de 'Seq'
TestLayer.cpp(337): message : vea la declaración de 'R'
TestLayer.cpp(356,14): error C2672: 'Seq': no se encontró una función sobrecargada que coincida
TestLayer.cpp(356,14): error C2783: 'std::function<R(Stream *)> Seq(T...)': no se pudo deducir el argumento de plantilla para 'R'
TestLayer.cpp(338): message : vea la declaración de 'Seq'
TestLayer.cpp(356,12): error C2530: 'seq': se deben inicializar las referencias
TestLayer.cpp(360,11): error C3536: 'seq': no se puede usar antes de inicializarse
TestLayer.cpp(360,2): error C2672: 'parse': no se encontró una función sobrecargada que coincida
TestLayer.cpp(360,20): error C2784: 'T parse(std::function<T(Stream *)>,Stream *)': no se pudo deducir el argumento de plantilla para 'std::function<T(Stream *)>' desde 'int'
TestLayer.cpp(293): message : vea la declaración de 'parse'

Edit:

So, thanks to the comments I came up with this solution:

template <typename ...T>
auto Seq(T... a) -> std::function<decltype(std::tuple{ a(std::declval<Stream*>())... })(Stream*)>
{
    return [=](Stream* stream) -> decltype(std::tuple{ a(std::declval<Stream*>())... }) {
        std::tuple tuple = { a(stream)... };

        return tuple;
    };
}

I don't know if it's the optimal solution.

CodePudding user response:

In C 11 you can figure out what std::functions R parameter is supposed to be in different places. I've chosen to make it a template parameter with a default type:

template<
    typename... T,
    class R = decltype(std::make_tuple(std::declval<T>()(std::declval<Stream*>())...))
>
auto Seq(T... a) -> std::function<R(Stream*)>
{
    return [=](Stream* stream) {
        return std::make_tuple(a(stream)...);
    };
}

Here's an alternative version without that extra template parameter:

template<typename... T>
auto Seq(T... a) ->
    std::function<
        decltype(
            std::make_tuple(std::declval<T>()(std::declval<Stream*>())...)
        )(Stream*)
    >
{
    return [=](Stream* stream) {
        return std::make_tuple(a(stream)...);
    };
}

In C 17 it is simpler:

template<typename... T>
auto Seq(T... a) {
    return std::function([=](Stream* stream) {
        return std::make_tuple(a(stream)...);
    });
}
  • Related