简体   繁体   English

将std :: strings的std :: vector解析为任意类型的std :: tuple

[英]Parsing std::vector of std::strings into std::tuple of arbitrary types

I'm writing a command-line interpreter. 我正在写一个命令行解释器。 In the old C++03 days you had to declare a fixed prototype and then parse arguments inside it. 在旧的C ++ 03天,您必须声明一个固定的原型,然后在其中解析参数。 But in C++11 we have variadic templates, so I wanted to write the code that will work with any function prototype and will automatically parse all arguments using std::stringstream. 但是在C ++ 11中我们有可变参数模板,所以我想编写适用于任何函数原型的代码,并使用std :: stringstream自动解析所有参数。

So far, I got the following code: 到目前为止,我得到了以下代码:

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <tuple>
#include <functional>

template <typename... Args>
class Command
{
public:
    Command(std::function<void(Args...)> callback, std::tuple<Args...> args)
        : callback(callback), args(args)
    {
    }
    void Execute(std::vector<std::string> call)
    {
        Parse(std::integral_constant<std::size_t, std::tuple_size<decltype(args)>::value - 1>{}, args, call);
        CallFunc(GenerateArgumentIndexPack<std::tuple_size<decltype(args)>::value>::Pack());
    }
private:
    std::function<void(Args...)> callback;
    std::tuple<Args...> args;

    template <typename T>
    void Fill(const std::string& input, T& output)
    {
        std::stringstream stream;
        stream << input;
        stream >> output;
    }

    template<std::size_t N, typename... Ts>
    void Parse(std::integral_constant<std::size_t, N>, std::tuple<Ts...>& info, std::vector<std::string>& tokens)
    {
        Fill(tokens[N], std::get<N>(info));
        Parse(std::integral_constant<std::size_t, N - 1>{}, info, tokens);
    }

    template<typename... Ts>
    void Parse(std::integral_constant<std::size_t, 0>, std::tuple<Ts...>& info, std::vector<std::string>& tokens)
    {
        Fill(tokens[0], std::get<0>(info));
    }

    template <std::size_t... ArgumentIndexes>
    struct ArgumentIndexPack {};

    template <std::size_t NumberOfArgumentIndexesToGenerate, std::size_t... GeneratedArgumentIndexes>
    struct GenerateArgumentIndexPack : GenerateArgumentIndexPack<NumberOfArgumentIndexesToGenerate - 1, NumberOfArgumentIndexesToGenerate - 1, GeneratedArgumentIndexes...> {};

    template <std::size_t... GeneratedArgumentIndexes>
    struct GenerateArgumentIndexPack<0, GeneratedArgumentIndexes...>
    {
        using Pack = ArgumentIndexPack<GeneratedArgumentIndexes...>;
    };

    template <std::size_t... ArgumentIndexes>
    void CallFunc(ArgumentIndexPack<ArgumentIndexes...>)
    {
        callback(std::get<ArgumentIndexes>(args)...);
    }
};

void Foo(int a, float b)
{
    std::cout << a << ' ' << b;
}

int main(int argc, char* argv[])
{
    try
    {

        Command<int, float> cmd1(&Foo, std::make_tuple(1, 2.0f));
        cmd1.Execute({"3", "4.0"});
    }
    catch (std::exception& e)
    {
        std::cerr << "Exception: " << e.what();
    }
    catch (...)
    {
        std::cerr << "Unknown exception.";
    }
}

The compile errors are: 编译错误是:

/home/fatony/Stuff/C++/Test/Src/Main.cpp: In instantiation of ‘void Command<Args>::Execute(std::vector<std::basic_string<char> >) [with Args = {int, float}]’:
/home/fatony/Stuff/C++/Test/Src/Main.cpp:96:18:   required from here
/home/fatony/Stuff/C++/Test/Src/Main.cpp:34:84: error: dependent-name ‘Command<Args>::GenerateArgumentIndexPack<std::tuple_size<decltype (((Command<Args>*)this)->Command<Args>::args)>::value>::Pack’ is parsed as a non-type, but instantiation yields a type
   CallFunc(GenerateArgumentIndexPack<std::tuple_size<decltype(args)>::value>::Pack());
                                                                                ^
/home/fatony/Stuff/C++/Test/Src/Main.cpp:34:84: note: say ‘typename Command<Args>::GenerateArgumentIndexPack<std::tuple_size<decltype (((Command<Args>*)this)->Command<Args>::args)>::value>::Pack’ if a type is meant

There are two problems in your code. 您的代码中存在两个问题。 First: you should #include <sstream> . 首先:你应该#include <sstream>

Second: there is call of std::get<std::tuple_size<...>>(tuple) , that is incorrect, since there is no such index. 第二:调用std::get<std::tuple_size<...>>(tuple) ,这是不正确的,因为没有这样的索引。 You can fix it by using this 您可以使用此方法修复它

void Execute(std::vector<std::string> call)
{
    //auto size = call.size();
    Parse(std::integral_constant<std::size_t,
    std::tuple_size<decltype(args)>::value - 1>{}, args, call);
   //CallFunc(GenerateArgumentIndexPack<std::tuple_size<decltype(args)>::value>::Pack());
}

About your second error in CallFunc , this function should be 关于你在CallFunc的第二个错误,这个函数应该是

CallFunc(typename
GenerateArgumentIndexPack<std::tuple_size<decltype(args)>::value>::Pack());

as stated in compiler error. 如编译错误中所述。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM