如何正确地声明模板将函数类型作为参数(如std :: function)

bar*_*ney 18 c++ templates std-function

我发现在下面有一个简洁的语法并不简单:

std::function<int(float, bool)>
Run Code Online (Sandbox Code Playgroud)

如果我将该函数声明为:

template <class RetType, class... Args>
class function {};
Run Code Online (Sandbox Code Playgroud)

定义函数的模板类型是一种普通的语法:

function<int,float,bool> f;
Run Code Online (Sandbox Code Playgroud)

但它适用于部分模板专业化的奇怪技巧

template <class> class function; // #1

template <class RV, class... Args>
class function<RV(Args...)> {} // #2
Run Code Online (Sandbox Code Playgroud)

这是为什么?为什么我需要为模板提供一个空类型参数(#1),否则它将无法编译

Tar*_*ama 9

这就是语言设计的方式.主模板不能像这样对类型进行复杂的分解; 你需要使用部分专业化.

如果我理解正确,您只想编写第二个版本而无需提供主模板.但想想模板参数如何映射到模板参数:

template <class RV, class Arg1, class... Args>
class function<RV(Arg1, Args...)> {}

function<int(float,bool)>; //1
function<int, float, bool>; //2
Run Code Online (Sandbox Code Playgroud)

选项1是您要编写的内容,但请注意,您将单个函数类型传递给模板,其中参数是两个类型参数和一个类型参数包.换句话说,在没有主模板的情况下编写它意味着您的模板参数不一定与模板参数匹配.选项2与模板参数匹配,但与专业化不匹配.

如果您有多个专业化,这就更没意义了:

template <class RV, class Arg1, class... Args>
class function<RV(Arg1, Args...)> {}

template <class T, class RV, class Arg1, class... Args>
class function<RV (T::*) (Arg1, Args...)> {}
Run Code Online (Sandbox Code Playgroud)

您可以想出一些规则来推断专业化的主要模板,但这对我来说似乎非常糟糕.


Rei*_*ica 8

你必须记住这int (float, bool)是一种类型.更确切地说,它是类型"函数,该函数类型的两个参数floatbool和回报int."

由于它是一种类型,因此模板必须在您要使用语法的位置具有一个类型参数int (float, bool).

同时,只有功能类型是笨重的.当然,你可以轻松地做到.例如,如果您需要做的只是某种转发器:

template <class T>
struct CallForwarder
{
  std::function<T> forward(std::function<T> f)
  {
    std::cout << "Forwarding!\n";
    return f;
  }
};
Run Code Online (Sandbox Code Playgroud)

但是,只要您想要访问函数类型的"组件",就需要为它们引入标识符.最自然的方法是对函数类型进行部分特化,就像你在问题中所做的那样(同样std::function如此).


Hol*_*olt 6

你实际上可以这样做:

template <typename T>
class X { };

X<int(char)> x;
Run Code Online (Sandbox Code Playgroud)

X你的定义中你可以创建一个std::function<T>你创建的std::function<int(char)>.这里的问题是你不能(至少很容易)访问参数(intchar这里)的返回类型和参数类型.

使用"技巧",您可以毫无问题地访问它们 - 它"简单地"使您的代码更清晰.