2014-01-21 3 views
0

std::tuple에 함수를 적용하는 함수를 작성했습니다 (기반은 "unpacking" a tuple to call a matching function pointer). 튜플이 복사 될 우려가 있습니다. 나는 동작 의미론이 무엇을하는지에 대한 아주 기본적인 생각을 가지고 있으며, 일반적으로 발견되는 문자열 예제에서 & & 및 rvalue와 같은 개념을 이해합니다. 그러나 나는 std :: forward()와 같은 것들이 어떻게 작동하는지에 대해 많이 모른다. 그리고 포장 및 variadic 프로그래밍이있을 때 어떻게 처리해야할지 모르겠습니다. (나는 약간의 표준을 추가했다 :: forward와 & &의 주위에 그리고 곧 컴파일 오류를 얻는다.)다음 코드에서 std :: tuple이 C++ 11 시맨틱을 사용하는지 확인하십시오.

사람은 튜플을위한 움직이는 의미가 작동하게하는 방법을 여기에서 설명 할 수 있냐? 한 가지 추가 질문은 코드의 튜플에 실제로 움직이는 의미가 실제로 작동하는지 (시각적 인 코드 검사 제외) 어떻게 확인할 수 있습니까?

미리 감사드립니다.

#include <tuple> 
#include <iostream> 
#include <functional> 

template<int ...> struct seq {}; 

template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {}; 

template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; }; 

template <typename R, typename Tp, typename ...FArgs> 
struct t_app_aux { 
    template<int ...S> 
    R static callFunc(std::function<R (FArgs...)> f,Tp t,seq<S...>) { 
    return f(std::get<S>(t) ...); 
    } 
}; 

template <typename R, typename Tp, typename ...FArgs> 
R t_app(std::function<R (FArgs...)> f, Tp t) { 
    static_assert(std::tuple_size<Tp>::value == sizeof...(FArgs), "type error: t_app wrong arity"); 
    return t_app_aux<R, Tp, FArgs...>::callFunc(f,t,typename gens<sizeof...(FArgs)>::type()); 
} 

int main(void) 
{ 
    std::tuple<int, float, double> t = std::make_tuple(1, 1.2, 5); 
    std::function<double (int,float,double)> foo1 = [](int x, float y, double z) { 
    return x + y + z; 
    }; 
    std::cout << t_app(foo1,t) << std::endl; 
} 
+0

리소스가없는 기본 유형 (int, double, std :: array 등)을 사용할 때 move가 copy와 동일하다는 것을 알고 있습니까? 따라서이 특정 코드 스 니펫에는 이동이 불가능합니다. – Mikhail

답변

2

현재 구현 사본이 있습니다 http://ideone.com/cAlorb 내가 일부 로그와 유형 추가 : 이전도

struct foo 
{ 
foo() : _value(0) { std::cout << "default foo" << std::endl; } 
foo(int value) : _value(value) { std::cout << "int foo" << std::endl; } 
foo(const foo& other) : _value(other._value) { std::cout << "copy foo" << std::endl; } 
foo(foo&& other) : _value(other._value) { std::cout << "move foo" << std::endl; } 

int _value; 
}; 

및/신청 후 :

std::cout << "Function created" << std::endl; 
std::cout << t_app(foo1,t) << std::endl; 
std::cout << "Function applied" << std::endl; 

그것은 제공합니다 :

Function created 
copy foo 
copy foo 
7.2 
Function applied 

그래서 다음이 앞으로 이런 식으로 이루어집니다를 부가 수정 :

template <typename R, typename Tp, typename ...FArgs> 
struct t_app_aux { 
    template<int ...S> 
    R static callFunc(std::function<R (FArgs...)> f, Tp&& t, seq<S...>) { 
    return f(std::get<S>(std::forward<Tp>(t)) ...); 
    } 
}; 

template <typename R, typename Tp, typename ...FArgs> 
R t_app(std::function<R (FArgs...)> f, Tp&& t) 
{ 
static_assert(std::tuple_size<typename std::remove_reference<Tp>::type>::value == sizeof...(FArgs), 
       "type error: t_app wrong arity"); 

    return t_app_aux<R, Tp, FArgs...>::callFunc(f, std::forward<Tp>(t), typename gens<sizeof...(FArgs)>::type()); 
} 

당신이 그것을 볼 수 있듯이 원치 않는 사본을 제거합니다 http://ideone.com/S3wF6x

Function created 
7.2 
Function applied 

유일한 문제는 static_assert 때문에 std::tuple_size이었다 처리했다 std::tuple<>&에 전화했는데 작동하지 않았습니다. 내가 typename std::remove_reference<Tp>::type을 사용했지만 어쩌면 영리하고 보편적 인 방법이 있을까요?

+1

'std :: decay '대신에'std :: remove_reference' 대신'cv-qualification '을 없애 좋은 무결점 유형을 제공하기를 제안합니다. – Casey

+0

@Johan 고마워요. 데이터를 보강하는 것이 좋습니다. 코드의 변경과 관련하여'tp'가 선언 될 때마다 'Tp'를'Tp &&'로 변경하고 't'를 사용하는 곳이면'forward (t)'로 변경하는 일반적인 규칙은 무엇입니까? – tinlyx

+0

@TingL 예, 복사를 원하지 않을 때마다 예를 들어 말할 것입니다. 듀오 Type && 및 std :: forward 이 도움이 될 것입니다. [범용 참조에 대한 Scott Meyers 프레젠테이션] (http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Scott-Meyers-Universal-References-in-Cpp11)에서 나는 너무 많은 헛소리를 말하지 않고 있는지 확인한다. – Johan

관련 문제