简体   繁体   English

C ++函数模板特化声明和模板参数; none vs. <> vs. <type>

[英]C++ function template specialization declarations and template arguments; none vs. <> vs. <type>

When studying function templates, I see specializations declared in different ways: 在研究函数模板时,我看到以不同方式声明的特化:

template<> void f(argtype) {}
template<> void f<>(argtype) {}
template<> void f<argtype>(argtype) {}

... and I wonder about the differences between these. ......我想知道这些之间的区别。 Given the below example with template functions with and without parameter, I have a few questions. 给出以下带有和不带参数的模板函数的例子,我有几个问题。

#include <iostream>
#include <typeinfo>

//Function print1 WITH function parameter---------------------------------------------
template<class T>
void print1(T) { std::cout << "Primary template for print1() with type " << typeid(T).name() <<  std::endl; }

template<>
void print1<int>(int) { std::cout << "Specialization for print1<int>(int)" << std::endl; }

//Not allowed, deduced to be the same as print1<int>(int)
/*template<>
void print1<>(int) { std::cout << "Specialization for print1<>(int)" << std::endl; }*/

//Not allowed, deduced to be the same as print1<int>(int)
/*template<>
void print1(int) { std::cout << "Specialization for print1(int)" << std::endl; }*/

//Function print2 WITHOUT function parameter------------------------------------------
/*Not allowed together with print<>(); compiler complains: 
    t2.cpp:29:6: error: template-id 'print2<>' for 'void print2()' does not match any template declaration*/
/*template<class T>
void print2() { std::cout << "Primary template for print2()" << std::endl; }*/

template<class T = short> //Declaration of print2<>() now ok in conjunction with print2<>()
void print2() { std::cout << "Primary template for print2()" << std::endl; }

template<>
void print2<int>() { std::cout << "Specialization for print2<int>()" << std::endl; }

template<>
void print2<>() { std::cout << "Specialization for print2<>()" << std::endl; }

int main() {
    //These three work in the same way, no matter which call method we use, so far so good
    print1(10);
    print1<>(10);
    print1<int>(10);
    print1(true);
    print1<>(true);
    print1<bool>(true);

    print2(); //Triggers print2<>(), a bit unexpectedly, should trigger print2<short>() (primary template)
    print2<>(); //Triggers print2<>(), a bit unexpectedly, should trigger print2<short>() (primary template)
    print2<bool>(); //Triggers print2<bool>() primary template
    print2<short>(); //Triggers print2<>(), should definately trigger primary template for print2()
    print2<int>(); //Triggers print2<int>() specialization
    return 0;
}

outputs: 输出:

Specialization for print1<int>(int)
Specialization for print1<int>(int)
Specialization for print1<int>(int)
Primary template for print1() with type b
Primary template for print1() with type b
Primary template for print1() with type b
Specialization for print2<>()
Specialization for print2<>()
Primary template for print2()
Specialization for print2<>()
Specialization for print2<int>()
  • What special meaning is derived from leaving the template specialization argument empty, non-existent or with the specialized type and how does it effect the outcome? 将模板特化参数保留为空,不存在或具有特殊类型以及它如何影响结果会产生什么特殊含义? It seems that with a function argument, this specification is superfluous and the compiler deduces it no matter how it's specified (with the result that equivalent explicit specifications become unallowed redeclarations). 似乎使用函数参数,此规范是多余的,无论指定方式如何,编译器都会推导出它(结果是等效显式规范成为不允许的重新声明)。
  • I understand that given a function without parameters, the specialized template argument is needed explicitly in declaration to specify for which instantiation the defined function applies to (since it can't be deduced otherwise). 我理解,给定一个没有参数的函数,在声明中明确需要专门的模板参数来指定定义的函数适用于哪个实例化(因为它不能以其他方式推断)。 But the meaning seems to imply something more in this case and the "empty" specialization (<>) is triggered in a somewhat unforeseen ways. 但在这种情况下,意义似乎意味着更多的东西,而“空”的专业化(<>)是以某种无法预料的方式触发的。 How come? 怎么会?
  • Why do I have to have a default template parameter when specializing print2 with print2<>() but not without it? 为什么在使用print2 <>()专门化print2时必须有一个默认的模板参数,但不是没有它?

What special meaning is derived from leaving the template specialization argument empty, non-existent or with the specialized type and how does it effect the outcome? 将模板特化参数保留为空,不存在或具有特殊类型以及它如何影响结果会产生什么特殊含义?

If you do provide a template argument list completely then you're simply explicitly specializing the function template for a given set of template arguments. 如果您确实提供了完整的模板参数列表,那么您只需要为定的模板参数集明确地专门化函数模板。

If you provide arguments for a (possibly empty) subset of the template parameters then you are explicitly specializing the function template for a set of arguments that has to be deduced . 如果为模板参数的(可能为空)子集提供参数,那么您将明确地为一组必须推导出的参数专门化函数模板。 According to [temp.deduct.decl]: 根据[temp.deduct.decl]:

In a declaration whose declarator-id refers to a specialization of a function template, template argument deduction is performed to identify the specialization to which the declaration refers. 声明者id引用函数模板的特化的声明中,执行模板参数推导以识别声明引用的特化。 Specifically, this is done for explicit instantiations (14.7.2), explicit specializations (14.7.3), and certain friend declarations (14.5.4). 具体来说,这是为了显式实例化(14.7.2),显式特化(14.7.3)和某些朋友声明(14.5.4)。 […]. [...]。 In all these cases, P is the type of the function template being considered as a potential match and A is […] the function type from the declaration […]. 在所有这些情况下, P是被认为是潜在匹配的函数模板的类型, A是来自声明[...]的函数类型。
The deduction is done as described in 14.8.2.5. 扣除按照14.8.2.5中的描述完成。

If, for the set of function templates so considered, there is either no match or more than one match after partial ordering has been considered (14.5.6.2), deduction fails and, in the declaration cases, the program is ill-formed. 如果对于所考虑的功能模板集合,在考虑部分排序后(14.5.6.2),没有匹配或多于一个匹配,则扣除失败,并且在声明情况下,程序是不正确的。

So for every parameter for which no argument was given, or in the case where no list is specified at all, template argument deduction is done for each corresponding parameter of the specialization and its counterpart from the primary template. 因此,对于没有给出参数的每个参数,或者在根本没有指定列表的情况下,对于特化的每个相应参数及其与主模板的对应参数进行模板参数推导。 The process is described in §14.8.2.5 and works just as if we called the primary template with the provided template argument list as the template arguments and objects of the types of the parameters in the specialization as the function arguments. 该过程在§14.8.2.5中描述,就像我们使用提供的模板参数列表作为模板参数和专业化中参数类型的对象作为函数参数调用主模板一样。

You should be familiar with the fact that one can call a function template with some of the template arguments specified, eg 您应该熟悉一个事实,即可以使用指定的某些模板参数调用函数模板,例如

template <typename A, typename B> void foo(A, B);

foo(7684, 48.);
foo<int>(7684, 48.);
foo<int, double>(7684, 48.);

That works equivalently for explicit specializations: 这相当于显式特化:

template <typename T, typename U>
void foo(T, U) {}

// Both template arguments have to be deduced.
template<> void foo(double, float);

// The *exact* same as above.
// template<> void foo<>(double, float);

// Second template argument has to be deduced by type.
// If we call foo<int>(int(), float()) then the deduced specialization is
// foo<int, float>, thus U=float.
template<> void foo<int>(int, float);

template<> void foo<int, int>(int, int);

This can also be applied to overloads of a function template. 这也可以应用于函数模板的重载。 In an attempt to find the primary template a specialization is corresponding to, the most specialized one is chosen. 为了找到专业化对应的主要模板,选择最专业的模板。

template <typename T, typename U>
void foo(T&, U&) {}

template <typename T, typename U>
void foo(T const&, U&) {}

// Specializes the second overload because it is more specialized.
template <>
void foo(int const&, float&);

Note that while looking for a primary template, the arguments provided (ie not to be deduced) are used to check the resulting function parameter of the primary template against the resulting function parameter of the specialization. 请注意,在查找主模板时,使用提供的参数(即不推断)来检查主模板的结果函数参数与特化的结果函数参数。 They have to be equal. 他们必须是平等的。

template <typename T, typename U>
void foo(T&, U&) {}

// Error - no matching primary template found.
template <>
void foo<int, int>(float&, int&);

// Dito:
template <>
void foo<int>(int, int&);

It seems that with a function argument, this specification is superfluous and the compiler deduces it no matter how it's specified (with the result that equivalent explicit specifications become unallowed redeclarations). 似乎使用函数参数,此规范是多余的,无论指定方式如何,编译器都会推导出它(结果是等效显式规范成为不允许的重新声明)。

Yes, that is indeed the case. 是的,情况确实如此。 Consider that if you specify a template argument invalidly that results in an error: 请考虑如果您无效地指定模板参数会导致错误:

But the meaning seems to imply something more in this case and the "empty" specialization (<>) is triggered in a somewhat unforeseen ways. 但在这种情况下,意义似乎意味着更多的东西,而“空”的专业化(<>)是以某种无法预料的方式触发的。 How come? 怎么会?

For a call, the template arguments are deduced first. 对于调用,首先推导出模板参数。 Then the specialization with those template arguments is called. 然后调用那些模板参数的特化。

If you explicitly specialized a function template for this particular specialization, here that is print2<> which is print2<short> , then that explicit specialization is thus called. 如果你明确地为这个特殊的专业化设置了一个函数模板,这就是print2<> ,它是print2<short> ,那么就会调用那个显式特化。
In what way is that unforeseen? 以何种方式无法预料?

Why do I have to have a default template parameter when specializing print2 with print2<>() but not without it? 为什么在使用print2<>()专门化print2时必须有一个默认的模板参数,但不是没有它?

Because the compiler cannot deduce the argument. 因为编译器无法推断出参数。 If you provide a default argument he doesn't have to deduce it in the first place. 如果你提供一个默认的说法,他没有推断它摆在首位。

What special meaning is derived from leaving the template specialization argument empty 将模板专门化参数留空是什么特殊含义

Missing arguments are deduced if possible; 如果可能,推断出缺失的论点; an empty argument list means that all arguments are to be deduced. 空参数列表表示要推导出所有参数。

non-existent 不存在的

That means you're declaring the primary template, not an explicit specialisation. 这意味着您要声明主要模板,而不是明确的专业化。

or with the specialized type 或者使用专门的类型

That means you're declaring an explicit specialisation for that type. 这意味着您要声明该类型的显式特化。

the "empty" specialization (<>) is triggered in a somewhat unforeseen ways. “空”特化(<>)以某种无法预料的方式触发。 How come? 怎么会?

In both cases, the template argument is deduced. 在这两种情况下,都推导出模板参数。 In print1 , the primary template declares that T is the same type as the function parameter; print1 ,主模板声明T与函数参数的类型相同; so it's deduced from the function parameter. 所以它是从函数参数中推导出来的。 In print2 , it's declared with a default type of short , so that is used. print2 ,它使用默认类型short ,因此使用它。 So your surprise at seeing print2<> when you think it should be print2<short> is explained: print2<> is print2<short> . 因此,当您认为print2<>应该是print2<short> print2<>时,您会惊讶地发现: print2<> print2<short>

Why do I have to have a default template parameter when specializing print2 with print2<>() but not without it? 为什么在使用print2 <>()专门化print2时必须有一个默认的模板参数,但不是没有它?

If there were neither a default argument nor a function parameters from which to deduce an argument, then it would be impossible to deduce a type for the specialisation, so <> couldn't be used. 如果既没有默认参数也没有从中推导出参数的函数参数,那么就不可能推导出专门化的类型,因此无法使用<> I don't know what you mean by "without it"; 我不知道你的意思是“没有它”; if you mean "without <> ", then you're declaring the primary template, not a specialisation, and the parameter is generic. 如果您的意思是“没有<> ”,那么您将声明主模板,而不是专业化,并且参数是通用的。

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

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