我正在编写一个命令行解释器。在旧的C ++ 03天,您必须声明一个固定的原型,然后在其中解析参数。但是在C ++ 11中我们有可变参数模板,所以我想编写适用于任何函数原型的代码,并使用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
答案 0 :(得分:2)
您的代码中存在两个问题。
首先:你应该#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());
如编译错误中所述。