C++ C++;函数模板专门化声明和模板参数;无与<&燃气轮机;vs.<;类型>;

C++ C++;函数模板专门化声明和模板参数;无与<&燃气轮机;vs.<;类型>;,c++,function,templates,template-specialization,C++,Function,Templates,Template Specialization,在研究函数模板时,我看到以不同方式声明的专门化: template<> void f(argtype) {} template<> void f<>(argtype) {} template<> void f<argtype>(argtype) {} template void f(argtype){ 模板void f(argtype){} 模板void f(argtype){} 。。。我想知道它们之间的区别。下面的例子中,有带参数

在研究函数模板时,我看到以不同方式声明的专门化:

template<> void f(argtype) {}
template<> void f<>(argtype) {}
template<> void f<argtype>(argtype) {}
template void f(argtype){
模板void f(argtype){}
模板void f(argtype){}
。。。我想知道它们之间的区别。下面的例子中,有带参数和不带参数的模板函数,我有几个问题

#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;
}
#包括
#包括
//带有函数参数的函数print1---------------------------------------------
模板
无效打印1(T){std::cout
将模板专用化参数保留为空有什么特殊意义

如果可能,将推导缺少的参数;空参数列表表示将推导所有参数

不存在

这意味着您要声明的是主模板,而不是明确的专业化

或者用专门的类型

这意味着您正在声明该类型的明确专业化

“空”专门化()是以某种不可预见的方式触发的。为什么

在这两种情况下,模板参数都是推导出来的。在
print1
中,主模板声明
T
与函数参数的类型相同;因此它是从函数参数推导出来的。在
print2
中,它是用默认类型
short
声明的,因此使用了它。因此,看到
print2
当您认为它应该是
print2
时,解释为:
print2
print2

为什么在使用print2()专门化print2时必须使用默认模板参数,而不是不使用它

如果既没有默认参数也没有函数参数来推断参数,那么就不可能推断出专门化的类型,因此不能使用
。我不知道“没有它”是什么意思;如果你是说“没有
”,然后声明主模板,而不是专门化,并且参数是泛型的

离开模板有什么特殊意义 专门化参数为空、不存在或带有专门化参数 类型以及它如何影响结果

如果您提供了一个完整的模板参数列表,那么您只需为给定的一组模板参数显式地专门化函数模板

如果您为模板参数的子集(可能为空)提供参数,那么您是在显式地专门化函数模板,以获得一组必须推导出的参数

在其声明器id引用 函数模板,执行模板参数推断以 标识声明所引用的专门化。 具体来说,这是为显式实例化(14.7.2)完成的, 显式专门化(14.7.3)和某些友元声明 (14.5.4)。[…]在所有这些情况下,
P
是函数的类型 被视为潜在匹配的模板和
a
是[…]的 声明[…]中的函数类型。
按照 如14.8.2.5所述

对于所考虑的函数模板集,如果 偏序后没有匹配项或有多个匹配项 考虑到(14.5.6.2),扣除失败,并且在申报情况下, 这个程序格式不好

因此,对于没有给出参数的每个参数,或者在根本没有指定列表的情况下,对专门化的每个对应参数以及主模板中的对应参数进行模板参数推断。该过程在§14.8.2.5中描述,就像我们使用pr调用主模板一样提供模板参数列表作为模板参数,并将专用化中参数类型的对象作为函数参数。

您应该熟悉这样一个事实,即可以使用指定的一些模板参数调用函数模板,例如

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

foo(7684, 48.);
foo<int>(7684, 48.);
foo<int, double>(7684, 48.);
模板void foo(A,B);
傅(7684,48.);
傅(7684,48.);
傅(7684,48.);
对显式专业化等效的:

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);
模板
void foo(T,U){}
//必须推导两个模板参数。
模板无效foo(双精度,浮动);
//*完全相同*如上所述。
//模板无效foo(双精度,浮动);
//第二个模板参数必须按类型推导。
//如果我们调用foo(int(),float()),那么推导出的专门化是
//foo,因此U=float。
模板void foo(int,float);
模板void foo(int,int);
这也适用于函数模板的重载。在尝试查找专门化所对应的主模板时,会选择最专门化的模板

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&);
模板
void foo(T&,U&){}
模板
void foo(T常数&,U&){}
//专门化第二个重载,因为它更专门化。
模板
void foo(int const&,float&);
请注意,在查找主模板时,提供的参数(即不可推导)用于检查主模板的结果函数参数与专用化的结果函数参数。它们必须相等

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&);
模板
void foo(T&,U&){}
//错误-找不到匹配的主模板。
模板
void foo(float&,int&);
//同上:
模板
无效foo(int,int&);

似乎对于函数参数,此规范是 多余的,无论如何指定,编译器都会对其进行推断 (其结果是等效的明确规范 不允许的重新声明)

是的,确实如此。如果您指定了一个无效的模板参数,则会导致错误:

但这个词的意思似乎暗示了更多的东西
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&);