2017-10-18 3 views
0

각기 다른 기본 형식 (int, float, bool, string)이 될 수있는 다양한 수의 인수를 사용하는 콘솔 명령을 설정하고 다른 번호를 지원하기 위해 8 개의 오버로드가있는 함수로 전달합니다 다양한 타입의 인자들. 명령 행 문자열을 유형에 따라 값으로 파싱 한 다음 함수에 전달하는 방법은 무엇입니까?가변 수와 유형의 인수를 템플릿 함수에 전달하는 방법은 무엇입니까?

const char* GetArg(int index) 함수를 통해 각 인수를 검색 할 수 있습니다. char*을 적절한 유형으로 변환하는 것은 문제가 아니므로 해당 부분에 대해 걱정할 필요가 없습니다. 값을 저장하고 어떻게 든 템플릿 함수에 전달하는 것은 내가 붙어있는 부분입니다.

예를 들어, 명령은 다음과 같은 문자열로 실행 된 경우 : "명령 66 진정한 5"문자열 값 "0.56"

그것은 다음 인수로 분해 될 어떻게 든 저장 것이다

:

int arg1 = GetArg(1); // 66 
bool arg2 = GetArg(2); // true 
int arg3 = GetArg(3); // 5 
char* arg4 = GetArg(4); // "string value" 
float arg5 = GetArg(5); // 0.56 

// The function definition looks something like this: 
void SomeFunc(); 
template<typename T1> 
void SomeFunc(const T1& arg1); 
template<typename T1, typename T2> 
void SomeFunc(const T1& arg1, const T2& arg2); 
// etc... 

// And then somehow it would be called. This is just an example. I don't 
// know how to call it in a way that would work with variable number and 
// type of args. 
switch (argCount) 
{ 
case 0: 
    SomeFunc(); 
    break; 
case 1: 
    SomeFunc(arg1); 
    break; 
case 2: 
    SomeFunc(arg1, arg2); 
    break; 
case 3: 
    SomeFunc(arg1, arg2, arg3); 
    break; 
case 4: 
    SomeFunc(arg1, arg2, arg3, arg4); 
    break; 
case 5: 
    SomeFunc(arg1, arg2, arg3, arg4, arg5); 
    break; 
} 

방법이 가능 할 것입니다 : 인수의 수에 따라 다음

그리고, 올바른 템플릿 함수를 호출? 각 인수의 유형을 알 수 있도록 템플릿 함수에 전달할 수있는 방법으로 args를 저장하는 것은 가능하지 않지만 나는 단지 무언가를 생각하고 있지 않은 것처럼 느낍니다.

이 인터페이스도 변경할 수 없습니다. 이것은 제가 다루어야 할 제 3의 기능입니다. 따라서 구현 방법에 관계없이 결국에는 SomeFunc()을 통과해야합니다.

중요 : Visual Studio 2012에서이 작업을 수행하므로 새로운 C++ 기능으로 제한됩니다. C++ 11을 조금이라도 할 수는 있지만 그게 전부입니다. 프로젝트를 최신 버전으로 업그레이드하려고하지만 당장은 그 문제를 해결해야합니다.

+0

컴파일 타임 및 런타임 로직을 혼합하려는 것처럼 들립니다. 템플릿은 컴파일 시간이며 컴파일 타임에 매개 변수의 수와 유형을 알아야합니다. 그것은 정말로 당신이 성취하고자하는 다른 것입니까? –

+0

튜플을 만들 수 있다면 [this] (https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer)를 사용하여 튜플을 전환 할 수 있습니다 함수 호출. – NathanOliver

+0

@TommyAndersen 소리가 정확합니다. 나는 그 주위에 어떤 방법도 없다. 나는 이벤트를 쉽게 트리거하기위한 도우미 콘솔 명령을 만들려고 노력하고있다. 각 이벤트마다 다양한 수의 args 및 유형을 가질 수있다. 이 문제가 해결되지 않으면 아이디어가 나온 것 같아 보일 것입니다. – Shenjoku

답변

1
using basic_type = std::variant<int, float, bool, std::string>; 

using flat_arguments = std::vector<basic_type>; 

template<std::size_t...Ns> 
using packed_arguments = std::variant< std::array<basic_type, Ns>... >; 

template<class T, std::size_t...Ns> 
std::array<T, sizeof...(Ns)> pack_one(std::vector<T> n, std::index_sequence<Ns...>) { 
    return {{ std::move(n[Ns])... }}; 
} 

template<class T, std::size_t...Ns> 
std::optional<std::variant< std::array<T, Ns>... >> 
pack_all(std::vector<T> n, std::index_sequence<Ns...>) { 
    std::optional<std::variant< std::array<T, Ns>... >> retval; 
    if (n.size() >= sizeof...(Ns)) { return retval; } 
    (
    (
     (n.size()==Ns)? 
     void(retval.emplace(pack_one(std::move(n), std::make_index_sequence<Ns>{}): 
     void() 
    ),... 
); 
    return retval; 
} 

flat_arguments get_arguments(int argc, char const* const*argv); // write this 

auto invoke_somefunc = [](auto&&...args){ 
    return SomeFunc(decltype(args)(args)...); 
}; 

int main(int argc, char const*const* argv) { 
    auto args = get_arguments(argc, argv); 
    auto args_packed = pack_all(std::move(args), std::make_index_sequence<9>{}); 
    if (!args_packed) return -1; 
    std::visit([](auto&& args){ 
    std::apply([](auto&&...args){ 
     std::visit(invoke_somefunc, args...); 
    }, args); 
    }, args_packed); 
} 

해야합니다. 아마도 오타가있을 것입니다. .

boost 일부 비틀기와, 상기 std 사용을 대체 할 수있는 상응하는 유형 (variantoptional)을 갖는다.

접이식 확장은 이상의 확장형 배열 해킹으로 대체 될 수 있습니다.

+0

죄송합니다, 저는 새로운 언어 기능에 대한 제한이 있음을 언급하는 것을 잊어 버렸습니다. VS2012에서이 작업을 수행하므로 대부분의 기능을 사용할 수 있다고 생각하지 않습니다. 그 정보로 원래 게시물을 업데이트했습니다. – Shenjoku

+0

@Shenjoku 아, 그렇다면 안돼. 내 말은, 당신이 아무것도 할 수있는 Turing Tar Pit이 있지만 기본적으로 스파게티 코드의 모든 엉망진창에 수동으로 위의 작업을 확장 할 수 있다는 것입니다. VS 2012에서 지원하는 C++의 하위 언어로 작성하는 것보다 C++ 컴파일러를 업그레이드하는 것이 훨씬 쉽습니다. 아마도 VS 2012에서 작동하는 변형을 지원하는 이전 버전의 부스트를 찾을 수 있고 수동으로 함수 객체를 작성하여 람다와 그 모든 고통을 대체 할 수 있습니다. – Yakk

관련 문제