有没有一种方法可以将模板化的函数签名作为模板模板参数传递

Is there a way to pass templated function signature as a template template parameter

本文关键字:函数 参数传递 一种 方法 有没有      更新时间:2023-10-16

通过使用模板模板参数,可以将模板化类传递给类,而无需在其参数上指定类型。我想知道是否有一种方法可以将函数的模板化签名传递到模板模板参数中,以便能够专门化要向前考虑的函数变体。

需要明确的是,我知道我不能这么做:

template <class T>
void foo() { /*...*/ }
template <template <class...> class FooType>
struct Foo { /*...*/ };
int main() {
    Foo<decltype(foo)> f;
}

但不知何故,我希望能够将函数的模板签名传递给Foo。这可能吗?

我不敢相信这是不可能的,所以我搜索了一下,找到了一种方法来做我想要的事情。我使用了模板using,语法为:

template <template<class... Args> class FooType>
struct Foo {
   FooType<int> ft;
};
template <class Res, class... Args>
using FooSignature = Res(*)(Args...);
int foo() {
   return 1;
}
int main() {
   Foo<FooSignature> f;
   f.ft = foo;
}

然而,这仍然留下了一个问题,因为标准中有相反的规定,这怎么可能呢。

在下面的例子中,有一个模板模板参数,它接受函数的首选签名
由于模板类的特殊化和缺少主体,因此只接受可调用的类型
这是OP实际要求的概括:

#include<cassert>
template<typename F>
struct S;
template<typename R, typename... Args>
struct S<R(Args...)> {
    using type = R(*)(Args...);
};
template<template<typename> class F>
struct T {
    typename F<void(int)>::type ft;
    typename F<double(double, double)>::type gt;
};
void f(int) { }
double g(double x, double y) { return x+y; }
int main() {
    T<S> t;
    t.ft = f;
    t.gt = g;
    t.ft(42);
    auto v = t.gt(1., 1.);
    assert(v == 2.);
}

从这个答案中可以看出

函数指针的模板在C++中是非法的

C++标准表示,为14/1美元

模板定义类或函数族。

进一步引用链接答案:

请注意,它并没有说"模板定义了一系列类、函数或函数指针"

然而,您可以传递具体的函数指针,并专门研究它们的签名:

#include <iostream>
template <class T>
void foo(T) { }
template <typename>
struct Foo;
template<typename T> 
struct Foo<void(T)> 
{
    void cb() { std::cout << "Tn"; }
};
template<> 
struct Foo<void(int)> 
{
    void cb() { std::cout << "intn"; }
};
template<> 
struct Foo<void(double)> 
{
    void cb() { std::cout << "doublen"; }
};
int main() 
{
    Foo<decltype(foo<int   >)>().cb(); // outputs 'int'
    Foo<decltype(foo<double>)>().cb(); // outputs 'double'
    Foo<decltype(foo<char  >)>().cb(); // outputs 'T'
    return 0;
}

template的模板仍然是一个模板。

template <class T>
void foo() { /*...*/ }
template <typename T>
struct Foo { /*...*/ };
int main() {
    Foo<decltype(foo<int>)> f;
}

不能将函数模板作为参数传递。可以做的是将函数模板包装在生成lambda中,并使用标记参数:

template <class T> struct tag_t { using type = T; };
template <class T>
void foo() { ... }
template <class F>
void call_func_with(F f) {
    f(tag_t<int>{} );
    f(tag_t<double>{} );
}
call_with_func([](auto tag) { foo<decltype(tag)::type>(); } );

这里,f(tag_t<X>{} )根据需要最终调用foo<X>()