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

标签 c++ templates c++11 variadic-templates

我正在编写一个命令行解释器。在旧的 C++03 时代,你必须声明一个固定的原型(prototype),然后解析其中的参数。但在 C++11 中,我们有可变参数模板,所以我想编写适用于任何函数原型(prototype)的代码,并将使用 std::stringstream 自动解析所有参数。

到目前为止,我得到了以下代码:

#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.";
    }
}

编译错误是:

/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

最佳答案

您的代码中有两个问题。 第一:你应该 #include <sstream> .

其次:有std::get<std::tuple_size<...>>(tuple)的调用,这是不正确的,因为没有这样的索引。您可以使用此修复它

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());
}

关于 CallFunc 中的第二个错误, 这个函数应该是

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

如编译器错误所述。

关于c++ - 将 std::strings 的 std::vector 解析为任意类型的 std::tuple,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23828702/

相关文章:

c++ - GLFW 窗口 glfwSwapBuffers() 真的很慢吗?

c++ - long long 和 long int 有什么区别

c# - 如何从我的 C# 单元测试中通过 SWIG 调试到 Quantlib

C++ 自定义单例

C++11 - 如何将 priority_queue 与共享指针 vector 一起使用?

python - <Array<float> 类型的 Swig 对象 *

c++ - 模板特化别名

c++ - 使用 qFromBigEndian 编译错误

c++ - 移动语义行为异常

c++ - 无堆粉刺。不正确还是迷信?