2012-12-30 100 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()); 
相关问题