2016-08-09 57 views
6

我不知道這個模式的名稱或者它是否存在。我需要一個函數返回一組將用於另一個函數的參數。例如,我有這樣的功能:獲取一組函數作爲結果的參數

void foo(int a, float b, some_class c); 

我想寫這樣的功能:

//Theoretical code: 
arguments get_arguments(){ 
    return arguments(0,0.0f, some_class()); 
} 

然後調用foo這樣的:

foo(get_arguments()); 

這可能嗎?如果是,如何?

+0

爲什麼需要通過返回值?另一種方法是通過引用'get_arguments'來傳遞'a','b'和'c',然後你可以簡單地調用'foo(a,b,c)'。爲了讓它成爲一個返回值或者使用std :: apply來查看元組對於靜態情況似乎沒有必要,因爲這樣做,不是嗎? –

+0

直接調用foo和您的解決方案有什麼不同? –

+0

不同之處在於,您將責任交給另一個函數來填充參數,這正是您在問題中提出的問題,不是嗎? –

回答

6

get_arguments可以std::make_tuple實現:

auto get_arguments(){ 
    return std::make_tuple(0,0.0f, some_class()); 
} 

這將返回一個std::tuple<int,float,some_class>

可以調用foo使用std::experimental::apply從C++ 17的參數:

std::experimental::apply(foo, get_arguments()); 

Live Demo

還有就是std::experimental::applyhere的實現,如果你需要一個。


要清理的電話,你可以添加一個轉發功能:

template <typename Tuple> 
void foo(Tuple&& t) { 
    return std::experimental::apply(
     static_cast<void(*)(int,float,some_class)>(&foo), 
     std::forward<Tuple>(t)); 
} 

然後你可以使用你想要的語法:

foo(get_arguments()); 

Live Demo

9

它可能可以通過使用std::tuple並重載foo函數來獲取元組並將其展開以調用實際的foo函數來完成。

+0

謝謝...沒有辦法沒有編輯foo? –

+1

也許和['std :: tie'](http://en.cppreference.com/w/cpp/utility/tuple/tie)結合使用 –

+0

@HumamHelfawi您不必編輯* original *'foo '函數,只是創建一個新的重載。 –

7

如果你的編譯器支持未來的C++ 17此外,還可以通過修改get_arguments()返回std::tuple和使用std::apply做到這一點:

std::apply(foo, get_arguments()) 
+0

這真的很棒!不幸的是沒有C++ 17可用,但非常感謝提到這一點。 –

1

多種方式實現同樣的東西

  1. 普通老式C++方式:返回一個包含多個變量
  2. C++ 11路的結構:使用std ::元組
  3. 升壓方式:使用boost ::融合

以最好的方式聲明的函數返回類型爲「自動」

2

樣品使用的元組,因爲我看到現在它立足於其他的想法,從這個問題代碼:

[live]

#include <iostream> 
#include <tuple> 

struct some_class{}; 

void foo(int a, float b, some_class c) { 
    std::cout << a << " " << b << "\n"; 
} 

decltype(auto) get_arguments() { 
    return std::make_tuple(0.1f, 0.2f, some_class{}); 
} 

template<typename T> 
void callFoo(const T& args) 
{ 
    foo(std::get<0>(args), std::get<1>(args), std::get<2>(args)); 
} 

int main() 
{ 
    callFoo(get_arguments()); 
} 
2

不是你叫什麼......但只是爲了好玩...使用std::bindstd::ref,您可以使用綁定bar()foo(),這樣

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

void foo(int a, float b, std::complex<double> c) 
{ std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl; } 

std::tuple<int, float, std::complex<double>> getArgs1() 
{ return std::make_tuple(1, 22.22f, std::complex<double>{333.333, 4444.4444}); } 

std::tuple<int, float, std::complex<double>> getArgs2() 
{ return std::make_tuple(4444, 333.333f, std::complex<double>{22.22, 1.1}); } 

int main() 
{ 

    std::tuple<int, float, std::complex<double>> t; 

    auto bar = std::bind(foo, 
         std::ref(std::get<0>(t)), 
         std::ref(std::get<1>(t)), 
         std::ref(std::get<2>(t))); 

    t = getArgs1(); 

    bar(); 

    t = getArgs2(); 

    bar(); 

    return 0; 
} 

的輸出爲

a = 1, b = 22.22, c = (333.333,4444.44) 
a = 4444, b = 333.333, c = (22.22,1.1) 

我再說一遍:只是爲了好玩。

2

std::tuple允許您將呼叫所需的參數打包到foo。正如其他人已經指出的那樣,有幾種方法可以調用你的函數,其中一些方法可能需要更新的標準。

在C++ 11中,你已經有了std::bind這應該適合你的需求,在你的情況下就好了。這裏有一個如何這可以實現一個例子:

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

class MyClass {}; 

std::tuple<int, float, MyClass> get_arguments() 
{ 
    int a = 0; 
    float b = 1.0f; 
    MyClass c; 
    // ... calculate parameters; 
    return std::make_tuple(a, b, c); 
} 

void foo(int a, float b, MyClass c) 
{ 
    std::cout << "a: " << a << ", b: " << b << "\n"; 
} 

int main(int argc, char* argv[]) 
{ 
    // get tuple holding arguments 
    auto arguments = get_arguments(); 

    // Binding arguments and calling directly 
    std::bind(
      foo, 
      std::get<0>(arguments), 
      std::get<1>(arguments), 
      std::get<2>(arguments))(); 

    return 0; 
} 

你可以把std::bind呼叫到一個包裝,特別是當你使用它頻繁。

如果最終傳遞來回參數包,將它們封裝到它們自己的數據類型甚至函數對象中可能是有意義的。此方法不需要std::tuplestd::bind,因此即使您無法訪問C++ 11,也可以使用該方法。

#include <iostream> 

class MyClass {}; 

void foo(int a, float b, MyClass c) 
{ 
    std::cout << "a: " << a << ", b: " << b << "\n"; 
} 

class FooCaller 
{ 
public: 
    void operator()(void) const 
    { 
     foo(a, b, c); 
    } 

    int a; 
    float b; 
    MyClass c; 
}; 

void get_arguments(FooCaller& fooCaller) 
{ 
    // ... calculate parameters; 
    fooCaller.a = 0.0f; 
    fooCaller.b = 1.0f; 
} 


int main(int argc, char* argv[]) 
{ 
    // Create Instance and calculate/retrieve arguments 
    FooCaller fooCaller; 
    get_arguments(fooCaller); 

    // call 'foo' 
    fooCaller(); 
    return 0; 
} 

這可能是更加通用的,但是這可能需要在介紹了C++ 11後來一些模板元編程功能。