2012-12-30 98 views
4

由於我選擇了一個令人誤解的問題標題,因此此問題已經以完全重複的方式關閉。這並沒有錯,但提出了一個經常討論的問題,例如在this question。由於內容是關於Stackoverflow中從未涉及的更具體的主題,因此我希望重新打開該問題。現在發生了,所以問題就出在這裏。通過單個函數返回另一個函數的幾個參數

我給出了一個函數,期望三個整數值作爲參數length(int x, int y, int z);。我無法修改此功能,例如接受任何作爲單個參數的結構或元組。

有沒有辦法在C++中編寫另一個函數,可以用作上述函數的單個參數,如length(arguments());

無論如何,該功能arguments();的返回類型似乎需要是int, int, int。但據我所知,我不能在C++中定義和使用這樣的函數。我知道我可以通過arguments()返回一個列表,一個元組,一個結構或一個類。問題被關閉了,因爲有些人認爲我會問這個問題。但困難的部分是傳遞元組或結構,或者作爲三個給定的整數參數。

這是可能的,如果是的話,在C++中如何可能?使用C++ 11的解決方案將會很好。

+0

每個問題都是重複這些天。 。 。 – Mob

+0

有人downvoted沒有評論,無論如何,你可以使用對象或結構來做到這一點 – vels4j

+0

@jogojapan是的,你是正確的。 – vels4j

回答

8

我不認爲這是在做你想做的任何直接的方式,但這裏是我在我的代碼一些地方使用C++ 11的技術。其基本思想是利用我已經叫call_on_tuple採取函數參數f以及進一步的參數的元組的模板功能,展開元組和調用的函數的參數的擴展列表上:

template <typename Fun, typename... Args, unsigned... Is> 
typename std::result_of<Fun(Args...)>::type 
call_on_tuple(Fun&& f, std::tuple<Args...>&& tup, indices<Is...>) 
{ return f(std::get<Is>(tup)...); } 

這樣的想法是不是調用

length(arguments()); 

你會打電話

call_on_tuple(length,arguments()); 

這假定arguments()是陳因此它返回一個std::tuple<int,int,int>(這基本上是你引用的問題的想法)。

現在困難的部分是如何獲得Is...參數包,這是一組整數0,1,2,...用於對元組的元素進行編號。

如果你確定你總是會有三個參數,你可以直接使用0,1,2,但是如果這個野心是爲了使它適用於任何n元函數,我們需要另一個技巧,例如在this post的幾個答案中。

這是一招變換參數的個數,即sizeof...(Args)成整數0,1,...,sizeof...(Args)列表

我就把這一招和call_on_tuple在命名空間detail實現:

namespace detail { 

    template <unsigned... Is> 
    struct indices 
    { }; 

    template <unsigned N, unsigned... Is> 
    struct index_maker : index_maker<N-1,N-1,Is...> 
    { }; 

    template <unsigned... Is> 
    struct index_maker<0,Is...> 
    { typedef indices<Is...> type; }; 


    template <typename Fun, typename... Args, unsigned... Is> 
    typename std::enable_if<!std::is_void<typename std::result_of<Fun(Args...)>::type>::value, 
       typename std::result_of<Fun(Args...)>::type>::type 
    call_on_tuple(Fun&& f, std::tuple<Args...>&& tup, indices<Is...>) 
    { return f(std::get<Is>(tup)...); } 
} 

現在實際功能call_on_tuple在全局名稱空間中定義,如下所示:

template <typename Fun, typename... Args> 
typename std::enable_if<!std::is_void<typename std::result_of<Fun(Args...)>::type>::value, 
      typename std::result_of<Fun(Args...)>::type>::type 
call_on_tuple(Fun&& f, std::tuple<Args...>&& tup) 
{ 
    using std::tuple; 
    using std::forward; 
    using detail::index_maker; 

    return detail::call_on_tuple 
    (forward<Fun>(f),forward<tuple<Args...>>(tup),typename index_maker<sizeof...(Args)>::type()); 
} 

它基本上調用detail::index_maker來生成遞增整數的列表,然後用那個調用detail::call_on_tuple

其結果是,你可以這樣做:

int length(int x, int y, int z) 
{ return x + y + z; } 

std::tuple<int,int,int> arguments() 
{ return std::tuple<int,int,int> { 1 , 2 , 3 }; } 

int main() 
{ 
    std::cout << call_on_tuple(length,arguments()) << std::endl; 
    return 0; 
} 

是希望足夠接近你需要的東西。

注意。我還添加了一個enable_if以確保僅用於實際返回值的函數f。您可以輕鬆地爲返回void的函數製作另一個實現。

抱歉再次提前關閉您的問題。

PS。您需要添加以下包含語句來測試此:

#include <tuple> 
#include <type_traits> 
#include <iostream> 
+1

複雜,但一個很好的把戲,以及:) – Veger

+0

感謝您分享您的想法和代碼。我甚至可以使用您的方法的修改版本來簡化我的實現的其他邏輯。 – danijar

1

你需要聲明一個struct { int a, b, c; }或類似的東西(一個類也可以) - 我認爲你已經編程了python或php等等。

-1

通過引用傳遞參數,以便您可以更改它們而不返回或返回結構。您只能從函數返回單個值。

+0

倒下投票人:謹慎解釋原因? – hari

4

這是不可能的,C++不允許本地提供3個返回值,它可以用作另一個函數的輸入參數3 單獨的

但有'技巧'返回多個值。儘管這些都不能爲您的問題提供完美的解決方案,因爲它們無法用作length()的單個參數而無需修改length()

使用的容器對象,就像一個structtupleclass

typedef struct { int a,b,c; } myContainer; 

myContainer arguments(int x, int y, int z) { 
    myContainer result; 
    result.a = 1; 
    // etc 
    return result; 
} 

myContainer c = arguments(x, y, z); 
length(c.a, c.b, c.c); 

,關鍵是要重載length()功能,所以它看起來像你可以用一個參數中使用它:

void length(myContainer c) { 
    length(c.a, c.b, c.c); 
} 

length(arguments()); 

當然,你可以通過使用inline,宏以及其他方法進一步優化它。

我知道它仍然不是你想要的,但我認爲這是最接近的方法。

+0

對不起,我的表述不清楚,但我不能修改'長度'功能。我已經更新了我的問題來說明問題。 – danijar

+2

@sharethis我已經更新了我的答案。使用函數重載可以*假*單參數長度函數... – Veger

+0

重載對於這個問題也是一個不錯的和簡單的(!)方法。自從jogojapan的回答給了我更多幫助之後,我給了你一個滿意的答覆。但這是我想的具體案例。 – danijar

-2

我們只能返回一個值。但如果你想返回多個值,可以使用數組或定義對象或結構

int* arguments() { 
     int x[1,4,6] 
     return x; 
    }; 

    void length(int i[]); 

    length(arguments()); 
1

大多數編程語言會通過某種形式的適配器功能的做到這一點。這是一個函數,它將作爲調用函數的參數(這裏是length)以及調用它的參數。你可以用C++來創建類似的模板。看看functional標題可以獲得靈感。

本地提供您正在尋找的語言是Perl。你可以寫:

sub arguments { 
    return 1, 2, 3; 
} 
sub length { 
    my ($p1, $p2, $p3) = @_; 
    # … Work with $p1, $p2 and $p3 
} 
length(arguments()); 
相關問題