Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 递归变量函数模板返回类型的decltype_C++_C++11_Variadic Templates_C++14_Decltype - Fatal编程技术网

C++ 递归变量函数模板返回类型的decltype

C++ 递归变量函数模板返回类型的decltype,c++,c++11,variadic-templates,c++14,decltype,C++,C++11,Variadic Templates,C++14,Decltype,给定以下代码(取自): #包括 #包括 #包括 #包括 #包括 #包括 模板 结构组合\u impl { compose_impl(Fs&&…Fs):functionTuple(std::forward_as_tuple(Fs…){ 模板 自动应用(标准:积分常数,Ts&&…Ts)常数 { 返回apply(std::integral_constant(),std::get(functionTuple)(std::forward(ts)…); } 模板 自动应用(标准:积分常数,Ts&&…Ts)常

给定以下代码(取自):

#包括
#包括
#包括
#包括
#包括
#包括
模板
结构组合\u impl
{
compose_impl(Fs&&…Fs):functionTuple(std::forward_as_tuple(Fs…){
模板
自动应用(标准:积分常数,Ts&&…Ts)常数
{
返回apply(std::integral_constant(),std::get(functionTuple)(std::forward(ts)…);
}
模板
自动应用(标准:积分常数,Ts&&…Ts)常数
{
返回std::get(functionTuple)(std::forward(ts)…);
}
模板
自动运算符()(Ts&&…Ts)常量
{
返回应用(std::integral_constant(),std::forward(ts)…);
}
std::tuple函数tuple;
};
模板
自动合成(Fs&&…Fs)
{
返回compose_impl(std::forward(fs)…);
}
int main()
{
auto f1=[](std::pair p){返回p.first+p.second;};
自动f2=[](双x){return std::make_pair(x,x+1.0);};
自动f3=[](双x,双y){返回x*y;};
自动g=合成(f1、f2、f3);

std::cout第一个选项的错误消息是由于

std::declval<func_type>()(std::forward<Ts>(ts)...)
注:

    编译并在GC4.4.1和Clang 3.5.0中使用C++ 11模式,在Visual C++ 2013上使用。
  • 如前所述,
    ret_hlp
    仅处理声明其
    运算符()
    的函数对象类型,类似于lambda闭包类型,但它可以轻松扩展到几乎任何其他类型,包括普通函数类型
  • 我试图尽可能少地更改原始代码;我认为关于该代码有一点需要提及:if
    compose
    被赋予左值参数(如本例所示),
    functionTuple
    内部的
    compose\u impl
    将存储对这些参数的引用。这意味着只要使用复合函子,原始函子就必须可用,否则将有悬空引用

编辑:根据评论中的要求,这里有关于最后一个注释的更多信息:

这种行为是由于转发引用的工作方式造成的,即
Fs&&…
函数参数的
compose
。如果您有一个
F&&
形式的函数参数,正在对其进行模板参数推导(如下所示),并且为该参数提供了一个
a
类型的参数,则:

  • 如果参数表达式是右值,
    F
    被推断为
    A
    ,当替换回函数参数时,它给出
    A&&
    (例如,如果将lambda表达式直接作为参数传递给
    compose
    ),则会发生这种情况
  • 如果参数表达式是一个左值,
    F
    被推导为
    A&
    ,当替换回函数参数时,它给出
    A&&
    ,根据规则产生
    A&
    (这是当前示例中的情况,因为
    f1
    和其他都是左值)
因此,在当前示例中,
compose\u impl
将使用推断的模板参数进行实例化,如下所示(使用lambda闭包类型的发明名称)

如果将lambda表达式作为参数直接传递给
compose
,那么根据上面的说明,
functionTuple
将具有以下类型

std::tuple<lambda_1_type&, lambda_2_type&, lambda_3_type&>
std::tuple<lambda_1_type, lambda_2_type, lambda_3_type>
结果是函数对象将始终被复制或移动到元组中,因此即使在原始组件被破坏之后,也可以使用生成的组合函数对象

哇,这太长了;也许你不应该说“精心设计”:)


编辑2作为OP的第二条注释:是的,原样的代码,没有
std::decay
(但正如您所说,扩展为正确确定普通函数参数的
ret_type
)将处理普通函数,但要小心:

int f(int) { return 7; }

int main()
{
    auto c1 = compose(&f, &f); //Stores pointers to function f.
    auto c2 = compose(f, f); //Stores references to function f.
    auto pf = f; //pf has type int(*)(int), but is an lvalue, as opposed to &f, which is an rvalue.
    auto c3 = compose(pf, pf); //Stores references to pointer pf.
    std::cout << std::is_same<decltype(c1.functionTuple), std::tuple<int(*)(int), int(*)(int)>>::value << '\n';
    std::cout << std::is_same<decltype(c2.functionTuple), std::tuple<int(&)(int), int(&)(int)>>::value << '\n';
    std::cout << std::is_same<decltype(c3.functionTuple), std::tuple<int(*&)(int), int(*&)(int)>>::value << '\n';
}
intf(int){return 7;}
int main()
{
auto c1=compose(&f,&f);//存储函数f的指针。
auto c2=compose(f,f);//存储对函数f的引用。
auto-pf=f;//pf的类型为int(*)(int),但它是一个左值,而&f是一个右值。
auto c3=compose(pf,pf);//存储对指针pf的引用。

std::我可以将此标记为已接受,因为它将我引向了正确的方向。您能详细说明一下第三条注释吗?您看到了更好的实现方法吗?谢谢您详细说明:)。作为补充说明,它的实现,以及返回类型的适当函数特性,也处理普通函数。
#include <cstddef>
#include <type_traits>
#include <tuple>
#include <iostream>
#include <utility>
#include <functional>

template<typename> struct ret_hlp;

template<typename F, typename R, typename... Args> struct ret_hlp<R (F::*)(Args...) const>
{
    using type = R;
};

template<typename F, typename R, typename... Args> struct ret_hlp<R (F::*)(Args...)>
{
    using type = R;
};

template<typename ... Fs>
struct compose_impl
{
    compose_impl(Fs&& ... fs) : functionTuple(std::forward_as_tuple(fs ...)) {}

    using f1_type = typename std::remove_reference<typename std::tuple_element<0, std::tuple<Fs...>>::type>::type;
    using ret_type = typename ret_hlp<decltype(&f1_type::operator())>::type;

    template<size_t N, typename ... Ts>
    ret_type apply(std::integral_constant<size_t, N>, Ts&& ... ts) const
    {
        return apply(std::integral_constant<size_t, N - 1>(), std::get<N>  (functionTuple)(std::forward<Ts>(ts)...));
    }

    template<typename ... Ts>
    ret_type apply(std::integral_constant<size_t, 0>, Ts&& ... ts) const
    {
        return std::get<0>(functionTuple)(std::forward<Ts>(ts)...);
    }

    template<typename ... Ts>
    ret_type operator()(Ts&& ... ts) const
    {
         return apply(std::integral_constant<size_t, sizeof ... (Fs) - 1>(), std::forward<Ts>(ts)...);
    }

    std::tuple<Fs ...> functionTuple;
};

template<typename ... Fs>
compose_impl<Fs ...> compose(Fs&& ... fs)
{
     return compose_impl<Fs ...>(std::forward<Fs>(fs) ...);
}

int main ()
{
    auto f1 = [](std::pair<double,double> p) {return p.first + p.second;    };
    auto f2 = [](double x) {return std::make_pair(x, x + 1.0); };
    auto f3 = [](double x, double y) {return x*y; };
    auto g = compose(f1, f2, f3);

    std::cout << g(2.0, 3.0) << std::endl;   //prints '13', evaluated as (2*3) + ((2*3)+1)
    return 0;
}
compose_impl<lambda_1_type&, lambda_2_type&, lambda_3_type&>
std::tuple<lambda_1_type&, lambda_2_type&, lambda_3_type&>
std::tuple<lambda_1_type, lambda_2_type, lambda_3_type>
std::tuple<typename std::decay<Fs>::type ...> functionTuple;
int f(int) { return 7; }

int main()
{
    auto c1 = compose(&f, &f); //Stores pointers to function f.
    auto c2 = compose(f, f); //Stores references to function f.
    auto pf = f; //pf has type int(*)(int), but is an lvalue, as opposed to &f, which is an rvalue.
    auto c3 = compose(pf, pf); //Stores references to pointer pf.
    std::cout << std::is_same<decltype(c1.functionTuple), std::tuple<int(*)(int), int(*)(int)>>::value << '\n';
    std::cout << std::is_same<decltype(c2.functionTuple), std::tuple<int(&)(int), int(&)(int)>>::value << '\n';
    std::cout << std::is_same<decltype(c3.functionTuple), std::tuple<int(*&)(int), int(*&)(int)>>::value << '\n';
}