简体   繁体   English

坚持使用 C++ 元编程

[英]stuck with C++ metaprogramming

I'm trying to get into TMP with a book called Practical C++ Metaprogramming and I'm stuck at trying to derive one of the first examples...我正在尝试通过一本名为Practical C++ 元编程的书进入 TMP,但我一直在尝试推导出第一个示例...

My objective is to make a templated function call taking a function with multiple parameters of unrelated type and then, to return the computation of that function with the parameters.我的目标是制作一个模板化的 function call ,调用一个带有多个不相关类型参数的 function,然后返回带有参数的 function 的计算。

What seems to be the root of the problem is that I'm unable to instantiate a struct (the good specialization of makeTupleOfParams ) with the appropriate parameter types that would allow me to define the type of the input function parameters, tupleOfParamTypes_t in my code.问题的根源似乎是我无法使用适当的参数类型实例化一个结构( makeTupleOfParams的良好专业化),这将允许我在我的代码中定义输入 function 参数的类型tupleOfParamTypes_t

I don't understand why this is the problem because the Function signature in the build output seems equivocal enough to identify the types of the arguments with the specialization <Return(Args...)> .我不明白为什么会出现这个问题,因为构建 output 中的 Function 签名似乎模棱两可,足以识别 arguments 的类型与 Ar 专业化<Return(Args...)> I don't get why this struct would not be generated with the correct member using type = std::tuple<Args...>;我不明白为什么using type = std::tuple<Args...>;不会使用正确的成员生成此结构which seems to be the key to all this.这似乎是这一切的关键。

Here's the whole thing:这是整个事情:

#include <tuple>

// base template
template<typename Function>
struct makeTupleOfParams;

// template specialization to identify parameters
template <typename Return, typename... Params>
struct makeTupleOfParams<Return(Params...)>
{
    using type = std::tuple<Params...>;
};

// shortcut to identify type of parameters
template <typename Function>
using tupleOfParamTypes_t = typename makeTupleOfParams<Function>::type;

// function to unroll a tuple of parameters on a function
template <typename Function, typename Params, size_t... Index>
auto dispatchParams(Function f, Params p, std::index_sequence<Index...>)
{
    return f(std::get<Index>(p)...);
}

template <typename Function, typename... Params>
auto call(Function f, Params... p)
{
    // getting size of Params and argument types of Function
    constexpr size_t paramsCount = sizeof...(Params);
    tupleOfParamTypes_t<Function> params;

    return dispatchParams(f, params, std::make_index_sequence<paramsCount>());
}

auto f(int i, float j) -> decltype(i+j)
{
    return i + j;
};

void main()
{
    call(f, 1, 2.0);
}

And the build output:以及构建 output:

1 > ------Build started : Project: TMP, Configuration : Debug Win32------
1 > main.cpp
1 > d:\git\meta - cpp - sandbox\src\main.cpp(40) : warning C4326 : return type of 'main' should be 'int' instead of 'void'
1 > d:\git\meta - cpp - sandbox\src\main.cpp(16) : error C2794 : 'type' : is not a member of any direct or indirect base class of 'makeTupleOfParams<Function>'
1 >     with
1 >     [
1 >         Function = float(__cdecl *)(int, float)
1 >     ]
1 > d:\git\meta - cpp - sandbox\src\main.cpp(28) : note: see reference to alias template instantiation 'tupleOfParamTypes_t<float(__cdecl *)(int,float)>' being compiled
1 > d:\git\meta - cpp - sandbox\src\main.cpp(41) : note: see reference to function template instantiation 'auto call<float(__cdecl *)(int,float),int,double>(Function,int,double)' being compiled
1 >     with
1 >     [
1 >         Function = float(__cdecl *)(int, float)
1 >     ]
1 > d:\git\meta - cpp - sandbox\src\main.cpp(26) : error C2938 : 'tupleOfParamTypes_t' : Failed to specialize alias template
1 > d:\git\meta - cpp - sandbox\src\main.cpp(31) : error C2672 : 'dispatchParams' : no matching overloaded function found
1 > d:\git\meta - cpp - sandbox\src\main.cpp(26) : error C2893 : Failed to specialize function template 'auto dispatchParams(Function,Params,std::integer_sequence<unsigned int,_Ix...>)'
1 > d:\git\meta - cpp - sandbox\src\main.cpp(26) : note: With the following template arguments :
1 > d:\git\meta - cpp - sandbox\src\main.cpp(26) : note: 'Function=float (__cdecl *)(int,float)'
1 > d:\git\meta - cpp - sandbox\src\main.cpp(26) : note: 'Params=unknown-type'
1 > d:\git\meta - cpp - sandbox\src\main.cpp(26) : note: 'Index={0, 1}'
1 > Done building project "TMP.vcxproj" --FAILED.
========== Build: 0 succeeded, 1 failed, 0 up - to - date, 0 skipped ==========

When you call your call function, you pass the function f as an argument.当您call function 时,您将 function f作为参数传递。 However c++ implicitly converts the argument to a pointer-to-function.然而 c++ 隐式地将参数转换为指向函数的指针。 Therefore, when the type-alias is being constructed, the template parameter is actually int(*)(int,float) , not int(int,float) .因此,在构造类型别名时,模板参数实际上是int(*)(int,float) ,而不是int(int,float) Since this does not meet the requirements of the partially specialised template, the compiler attempts to construct the type-alias from the non-specialised template for makeTupleOfParams.由于这不满足部分特化模板的要求,编译器尝试从非特化模板为 makeTupleOfParams 构造类型别名。 However the non-sepcialised template does not contain the type-alias "type", which results in a compile-error.但是,非专用模板不包含类型别名“type”,这会导致编译错误。

To solve, modify the partially-specialised template to:要解决此问题,请将部分专业化的模板修改为:

template<typename Return, typename... Params>
struct makeTupleOfParams<Return(*)(Params...)> //pointer-to-function specialisation
{
    using type = std::tuple<Params...>;
};

Another solution is to use type_traits to remove the pointer trait within the call function, like so:另一种解决方案是使用type_traits删除call function 中的指针特征,如下所示:

#include<type_traits>

template <typename Function, typename... Params>
auto call(Function f, Params... p)
{
    // getting size of Params and argument types of Function
    constexpr size_t paramsCount = sizeof...(Params);
    // modify function type to remove pointer trait
    tupleOfParamTypes_t<std::remove_pointer_t<Function>> params;

    return dispatchParams(f, params, std::make_index_sequence<paramsCount>());
}

In this case, the template parameter passed to tupleOfParamTypes_t will be int(int,float) .在这种情况下,传递给tupleOfParamTypes_t的模板参数将是int(int,float)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM