有没有办法将模板化的函数签名作为模板模板参数传递

时间:2016-04-29 19:05:35

标签: c++ templates

通过使用模板模板参数,可以将模板化的类传递给类,而无需在其参数上指定类型。我想知道有没有办法将函数的模板化签名传递给模板模板参数,以便能够专门考虑函数的哪个变体被认为是向前的。

要明确 - 我知道我做不到:

template <class T>
void foo() { /*...*/ }

template <template <class...> class FooType>
struct Foo { /*...*/ };

int main() {
    Foo<decltype(foo)> f;
}

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

5 个答案:

答案 0 :(得分:8)

我无法相信这是不可能的,所以我搜索了一下,找到了一种方法来做我想要的。我使用模板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;
}

然而,这仍然存在一个问题,即如何这可能是可能的,因为标准陈述了相反的东西。

答案 1 :(得分:7)

在下面的示例中,有一个模板模板参数,它接受该函数的首选签名 由于模板类的特殊化和缺少主体,因此只接受可调用类型 这是对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.);
}

答案 2 :(得分:4)

可以在this answer

中看到
  

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

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

  

模板定义了一系列类或函数。

进一步引用相关联的答案:

  

请注意,它没有说&#34;模板定义了一系列类,函数或函数指针&#34;

但是,您可以传递具体的函数指针,并专注于它们的签名:

#include <iostream>

template <class T>
void foo(T) { }

template <typename>
struct Foo;

template<typename T> 
struct Foo<void(T)> 
{
    void cb() { std::cout << "T\n"; }
};

template<> 
struct Foo<void(int)> 
{
    void cb() { std::cout << "int\n"; }
};

template<> 
struct Foo<void(double)> 
{
    void cb() { std::cout << "double\n"; }
};

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;
}

答案 3 :(得分:3)

模板模板仍然是模板。

template <class T>
void foo() { /*...*/ }

template <typename T>
struct Foo { /*...*/ };

int main() {
    Foo<decltype(foo<int>)> f;
}

答案 4 :(得分:2)

您无法将函数模板作为参数传递。你可以做的是将一个函数模板包装在一个带有标记参数的生成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>()