繁体   English   中英

提取模板化 function 中的输入参数类型,以 function 作为参数

[英]Extract type of input parameter in templated function taking a function as parameter

我有这个 function:

template<typename T, int (*F)(T&)>
void DoStuff(T& s)
{
    auto an = make_any<T>(s);
    cout << _GetDataFromAny<MyStruct, F>(an);
}

需要这样调用:

DoStuff<MyStruct, Fun>(s);

这很好用,但是我不喜欢指定第一种类型,因为它是第二个参数签名的一部分。 我希望能够推断出来,这样我就可以调用:

DoStuff<Fun>(s);

但是,我不知道如何在模板中指定需要从 function F 的签名中推导出类型 T。

这可能吗?

您可以编写一个助手来推断返回int的 function 指针的参数类型:

template<typename T>
T arg_type(int(*)(T&));

然后稍微重写您的 function 模板以将 function 指针作为非类型模板参数,并从中找出参数类型

template<auto F, typename T = decltype(arg_type(F))>
void DoStuff(T& s) {
 // ...
}

免责声明:这个答案经过了一系列的编辑和更正,非常感谢 Jarod42 的耐心和帮助,以及 cigien 的富有成果的讨论。 它比必要的时间长一点,但我觉得保留一点历史是值得的。 它是:最简单的/我更喜欢的/对先前混乱的一些解释。 如需快速回答,请阅读第二部分。


简单的

您可以为 function 指针使用auto模板参数(自 C++17 起),并从参数推导出T

template<auto F, typename T>
void DoStuff(T& s)
{
    int x = F(s);
}

int foo(double&){ return 42;}

int main() {
    double x;
    DoStuff<&foo>(x);
}

现场演示


正确的”

上面的缺点是FT是“独立的”。 您可以调用DoStuff<&foo>(y) ,例如std::string y; 并且实例化只会在调用F时失败。 这可能会导致不必要的复杂错误消息,具体取决于您对Fs实际操作。 要在将错误的T传递给DoStuff<F>时已经在调用站点触发错误,您可以使用特征来推断F的参数类型并直接将其用作DoStuff的参数类型:

template <typename T> struct param_type;

template <typename R,typename P>
struct param_type< R(*)(P&)> {
    using type = P;
};
    
template<auto F>
void DoStuff(typename param_type<decltype(F)>::type& s)
{
    int x = F(s);  // (1)
}

int foo(double&){ return 42;}    

int main() {
    double x;
    DoStuff<foo>(x);
    std::string y; 
    DoStuff<foo>(y);  // (2) error 
}

现在,之前只发生在模板 (1) 中的错误已经发生在main (2) 中,并且错误消息更加清晰。

现场演示


主要是出于好奇,考虑这种从function指针推导参数类型的方式:

template <typename T> struct param_type;

template <typename R,typename P>
struct param_type< R(*)(P&)> {
    using type = P;
};
    
template<auto F, typename T = typename param_type<decltype(F)>::type>
void DoStuffX(T& s)
{
}

int foo(double&){ return 42;}    

int main() {
    double x;
    DoStuffX<foo>(x);
}

这是我最初的答案,但它实际上并没有像我想象的那样做。 请注意,我实际上并没有在DoStuff中调用F ,令我惊讶的是,它编译了:

int main() {
    std::string x;
    DoStuffX<foo>(x);
}

原因是当可以从传递的参数中推断出T时,不使用默认模板参数(参见此处)。 也就是说, DoStuffX<foo>(x); 实际上实例化DoStuffX<foo,std::string> 我们仍然可以通过以下方式获得默认值:

int main() {
    std::string x;
    auto f_ptr = &DoStuffX<foo>;
    f_ptr(x);  // error
}

现在用std::string调用DoStuffX<foo>是一个编译器错误,因为这里DoStuffX<foo>被实例化为DoStuffX<foo,double> ,使用了默认参数(没有参数可以用来推断TDoStuffX被实例化时)。

暂无
暂无

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

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