2016-03-09 7 views
1

На основании этой статьи я попытался создать общий синтаксический анализатор, который выводит возвращаемое значение вызываемой функции в виде строки.void troubles возвращает значение в строку

Parsing std::vector of std::strings into std::tuple of arbitrary types

К сожалению, я не выяснить, как форматировать значения, возвращаемого функцией, которая возвращает аннулируются ...

template<class R, class T, class... Args> class CCmd { 
public: 
    CCmd(R (T::* fptr)(Args...), T * obj){} 

    auto call(Args&&... args) -> R { 

     auto func = std::mem_fun(mFunction); 

     return func(mObject, std::forward<Args>(args)...); 
    } 

protected: 

    R (T::* mFunction)(Args...); 

    T * mObject; 
}; 

И:

template< class R, class T, class... Args> class CCommand : public CCmd<R,T,Args...> { 

public: 
    CCommand(R (T::* fptr)(Args...), T * obj) : 
     CCmd<R,T,Args...>(fptr, obj) { 
    } 

    void Execute(std::vector<std::string> && parameters, std::string & returnValue) { 
     if(parameters.size() >= std::tuple_size<decltype(args)>::value) { 

      std::stringstream stream; 

      Parse(std::integral_constant<std::size_t, std::tuple_size<decltype(args)>::value - 1>{}, std::forward<decltype(args)>(args), std::forward<std::vector<std::string>>(parameters)); 

      /* the following line fails, if R is of type void */ 
      stream << CallFunc(typename GenerateArgumentIndexPack<std::tuple_size<decltype(args)>::value>::Pack()); 

      stream >> returnValue; 

     } else { 
      returnValue = "not enough parameters"; 
     } 
    } 




protected: 

    std::tuple<Args...> args; 

    template <typename X, typename Y> 
    void Fill(const Y && input, X & 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(std::forward<std::string>(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(std::forward<std::string>(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> 
    auto CallFunc(ArgumentIndexPack<ArgumentIndexes...>) -> R { 
     return CCmd<R,T,Args...>::call(std::forward<Args>(std::get<ArgumentIndexes>(args))...); 
    } 
}; 

A класс:

class CMyClass { 
public: 
    void voidFunc() { 
     std::cout << "CMyClass::voidFunc" << std::endl; 
    } 

    void voidDoubleFunc(double d) { 
     std::cout << "CMyClass::voidDoubleFunc(" << d << ")" << std::endl; 
    } 
}; 

главная:

int main(int argc, char** argv) { 

    CMyClass oMyClass; 
    CCommand<void, CMyClass> testObj0(&CMyClass::voidFunc,  &oMyClass); 
    CCommand<void, CMyClass, double> testObj3(&CMyClass::voidDoubleFunc, &oMyClass); 

    std::string retval; 

    // This fails as get on a tuple with 0 elements seems to be invalid 
    testObj0.Execute({}, retval); 
    // This doesn't compile, as the voidDoubleFunc returns void 
    testObj3.Execute({"1.23", retval); 

    return 0; 
} 

Компилятор вызова:

g++ -c src/main.cpp -o src/main.o -std=c++11 

Сообщение об ошибке (1) при вызове Execute на RT :: F(), где R не типа пустоты:

src/main.cpp: In instantiation of 'void CCommand<R, T, Args>::Parse(std::integral_constant<long long unsigned int, N>, std::tuple<_Args2 ...>&&, std::vector<std::basic_string<char> >&&) [with long long unsigned int N = 18446744073709551615ull; Ts = {}; R = void; T = CMyClass; Args = {}]': 
src/main.cpp:73:179: required from 'void CCommand<R, T, Args>::Execute(std::vector<std::basic_string<char> >&&, std::string&) [with R = void; T = CMyClass; Args = {}; std::string = std::basic_string<char>]' 
src/main.cpp:147:31: required from here 
src/main.cpp:98:68: error: no matching function for call to 'get(std::tuple<>&)' 
     Fill(std::forward<std::string>(tokens[N]), std::get<N>(info)); 

Сообщение об ошибке (2) при вызове Execute on void T :: f (Args ...), где Args ... не является недействительным:

src/main.cpp: In instantiation of 'void CCommand<R, T, Args>::Execute(std::vector<std::basic_string<char> >&&, std::string&) [with R = void; T = CMyClass; Args = {double}; std::string = std::basic_string<char>]': 
src/main.cpp:156:43: required from here 
src/main.cpp:76:11: error: no match for 'operator<<' (operand types are 'std::stringstream {aka std::basic_stringstream<char>}' and 'void') 
    stream << CallFunc(typename GenerateArgumentIndexPack<std::tuple_size<decltype(args)>::value>::Pack()); 
+1

Что вопрос? Это всего лишь куча кода, который компилируется. Что не работает так, как вы этого хотите? – Barry

+0

Извините, просто отредактировал какой-то код. Прежде всего, он не компилируется, так как Execute пытается вызвать поток << void; Во-вторых, он не компилируется, поскольку get вызывается в кортеже без элементов –

+0

@WernerPirkl, который может быть частью сообщения, а не комментария. Также: какой компилятор и флаги вы используете, и какое сообщение об ошибке вы получаете? –

ответ

0

Для вашей первой проблемы, то вам просто необходимо создать и перегрузки Parse:

void Parse(std::integral_constant<std::size_t, -1>, 
      std::tuple<>&& info, std::vector<std::string>&& tokens) { 
} 

Для вашей второй задачи (метод возвращения void), вы можете использовать промежуточный struct результата и специализироваться CCmd для void :

Intermediate структура ReturnOf:

template <typename R> 
struct ReturnOf { 
    typedef R return_type; 
}; 

template <> 
struct ReturnOf<void> { 
    typedef std::string return_type; 
}; 

Специализация CCmd для void:

template<class T, class... Args> class CCmd<void, T, Args...> { 
public: 
    CCmd(void (T::* fptr)(Args...), T * obj) : mFunction(fptr), mObject(obj) { } 

    auto call(Args&&... args) -> std::string { 
     auto func = std::mem_fun(mFunction); 
     func(mObject, std::forward<Args>(args)...); 
     return std::string(); 
    } 

protected: 
    void (T::* mFunction)(Args...); 
    T * mObject; 
}; 

И, наконец, в CCommand:

template <std::size_t... ArgumentIndexes> 
auto CallFunc(ArgumentIndexPack<ArgumentIndexes...>) 
    -> typename ReturnOf<R>::return_type { 
    ... 
} 
+0

Это прекрасно решает проблему! Большой! Большое спасибо! –