2014-01-21 68 views
0

我已經編寫了一個函數來將函數應用於std::tuple,如下所示(基於"unpacking" a tuple to call a matching function pointer)。 我擔心元組可能會被複制。我對移動語義的作用有一個非常基本的概念,並理解常見的字符串示例中的概念,如& &和右值。但我不太瞭解std :: forward()和類似的工作方式。如果還有包裝和可變編程,我不知道如何處理它。 (我添加了幾個std :: 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

你是否知道當你使用沒有資源的基本類型(即ints,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非常感謝。增加數據是個好主意。關於代碼的修改,在't'被聲明爲't'並且't'爲'forward'的情況下,將'Tp'更改爲'Tp &&'的一般規則爲(t)'哪裏使用't'? – tinlyx

+0

@TingL我會說是的,每次你不想複製,我認爲這兩個'類型&&'和'std :: forward '將有所幫助。看看[Scott Meyers關於Universal References的介紹](http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Scott-Meyers-Universal-References-in-Cpp11)到檢查我沒有說太多的廢話。 – Johan

相關問題