我发现在下面有一个简洁的语法并不简单:
std::function<int(float, bool)>
如果我将该函数声明为:
template <class RetType, class... Args>
class function {};
定义函数的模板类型是一种普通的语法:
function<int,float,bool> f;
但它适用于部分模板专业化的奇怪技巧
template <class> class function; // #1
template <class RV, class... Args>
class function<RV(Args...)> {} // #2
为什么? 为什么我需要为模板提供一个空类型参数(#1),否则它将无法编译
答案 0 :(得分:9)
这就是语言的设计方式。主模板不能对类型进行复杂的分解;你需要使用部分专业化。
如果我理解正确,您只想编写第二个版本而无需提供主模板。但请考虑模板参数如何映射到模板参数:
template <class RV, class Arg1, class... Args>
class function<RV(Arg1, Args...)> {}
function<int(float,bool)>; //1
function<int, float, bool>; //2
选项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...)> {}
您可能会想出一些规则来推断专业化的主要模板,但这对我来说似乎非常糟糕。
答案 1 :(得分:8)
您必须记住int (float, bool)
是类型。更确切地说,它是类型&#34;函数,它采用float
和bool
类型的两个参数,并返回int
。&#34;
由于它是一种类型,很明显模板必须在您所在的地方有 一个 类型参数想要使用语法int (float, bool)
。
同时,只有功能类型是笨重的。当然,你可以轻松地做到。例如,如果您需要做的只是某种转发器:
template <class T>
struct CallForwarder
{
std::function<T> forward(std::function<T> f)
{
std::cout << "Forwarding!\n";
return f;
}
};
但是,只要您想要访问&#34;组件&#34;在函数类型中,您需要一种为它们引入标识符的方法。最自然的方法是对函数类型进行部分特化,就像你在问题中所做的那样(就像std::function
那样)。
答案 2 :(得分:6)
你实际上可以这样做:
template <typename T>
class X { };
X<int(char)> x;
在X
的定义中,您可以像创建std::function<T>
一样创建std::function<int(char)>
。这里的问题是你不能(至少很容易)访问参数的返回类型和参数类型(int
和char
)。
使用&#34;技巧&#34;,您可以毫无问题地访问它们 - 它只是&#34;简单地&#34;让你的代码更清洁。
答案 3 :(得分:4)
&#34;为什么我需要为模板提供一个空类型参数&#34;
因为,您希望在&#34;返回类型&#34;之间进行显式类型区分。和#34;参数类型&#34;,具有相似的语法糖清晰度。在C ++中,template class
的第一手版本没有此类语法可用。你必须要专门化它,才能区分它。
阅读完Q后,我查看了<functional>
头文件。 偶std::function
做同样的伎俩:
// <functional> (header file taken from g++ Ubuntu)
template<typename _Signature>
class function;
// ...
/**
* @brief Primary class template for std::function.
* @ingroup functors
*
* Polymorphic function wrapper.
*/
template<typename _Res, typename... _ArgTypes>
class function<_Res(_ArgTypes...)>
正如您在评论中看到的那样,他们将专业版视为&#34; Primary&#34;类。因此,这个技巧来自标准标题本身!