gpt4 book ai didi

c++ - 函数重载匹配模板template

转载 作者:行者123 更新时间:2023-12-02 00:03:14 25 4
gpt4 key购买 nike

我希望第一个代码示例的最后两行打印相同的内容。

类型将按照我的预期进行扣除,并且过载解析度也将符合我的预期。
但是,如果我显式地键入限定函数调用的值,则推论出类型时,得到的结果将不同。

第二个代码示例重复该练习,以专用化替换重载分辨率。在这种情况下,一切都会按预期进行。

有什么解释吗?

编辑:我又增加了一行,显示Karthik提到的关于print<R,int>(r);的内容,我也不明白。

代码示例1 :(功能模板重载)

#include <iostream>
template <typename T>
void print (T i)
{
std::cout << "simple" << std::endl;
}
template <template<typename> class FF, typename TT>
void print (FF<TT> i)
{
std::cout << "template" << std::endl;
}
template <typename T1, typename T2>
void print (T1 a)
{
T2 b;
std::cout << "two type parameters" << std::endl;
}
template <>
void print<int>(int i)
{
std::cout << "int" << std::endl;
}
template <typename T>
struct R
{
T x;
};
int main()
{
R<int> r;
print<int>(1.1); // ok, prints "int"
print(1.1); // ok, prints "simple"
print<int>(1); // ok, prints "int"
print(1); // ok, prints "int"
print(r); // ok, prints "template"
print<int,int>(1); // ok, prints "two type parameters"
print<R<int>,int>(r); // ok, prints "two type parameters"
print<R<int> >(r); // (1) ?? why "simple" ??
print<R,int >(r); // (2) ?? prints "template", why does it compile at all ??
// gcc 4.6.2 (-std=c++0x) and 4.8.1 (-std=c++11)
// clang++ 3.3.1 same behavior as gcc
}

代码示例2 :(类模板专门化)。
#include <iostream>

template <typename T>
struct P
{
static void print (T i)
{
std::cout << "simple" << std::endl;
}
};
template <template<class TT> class FF, typename TT>
struct P <FF<TT> >
{
static void print (FF<TT> i)
{
std::cout << "template" << std::endl;
}
};
template <>
struct P<int>
{
static void print(int i)
{
std::cout << "int" << std::endl;
}
};
template <typename T>
struct R
{
T x;
};
int main()
{
R<int> r;
P<double>::print(1.1); // ok, prints "simple"
P<int>::print(1); // ok, prints "int"
P<R<int> >::print(r); // ok, prints "template"
//P<R,int >::print(r); // ok, does not compile
}

最佳答案

好吧,让我们看一下编译器对每一个的看法。

template <typename T> void print (T i); // (1)
template <template<typename> class FF, typename TT> void print (FF<TT> i); // (2)
template <typename T1, typename T2> void print (T1 a); // (3)
template <> void print<int>(int i); // (4)

好的,有一些预备知识:这里有三个函数模板,它们彼此重载(1、2和3),而4是1的特化。

所有三个重载都有一个功能参数。另外,这些函数具有模板参数:

1具有可从功能参数推导的单一类型模板参数。

2具有模板模板参数和类型模板参数,两者都可以从功能参数中推导出来。

3具有两个类型的模板参数,只能推导其中的第一个(使推论无效)。

现在让我们看一下电话。当有显式模板参数时,编译器将始终“预过滤”那些可以用这种方式实例化的函数的重载。
    print<int>(1.1);          // ok, prints "int"

一个显式类型模板参数。 1场比赛。 2不匹配,因为第一个参数不是模板。 3个匹配项,将 T1固定为 int;但是,无法推导 T2,因此它也消失了。选择参数 Tint的1。这匹配特化4。
    print(1.1);               // ok, prints "simple"

没有明确的模板参数。扣除开始;参数类型为 double。 1场比赛; T是 double 的。 2需要模式 FF<TT>,而 double与之不匹配,因此会失败。 3可以将 T1推导为 double,但是对于 T2没有任何帮助,因此它也失败了。选择1。专业不匹配。
    print<int>(1);            // ok, prints "int"

这与第一种情况相同,除了在最终重载解析期间会发生隐式转换。
    print(1);                 // ok, prints "int"

这与第二种情况相同,除了推导的类型是 int(仍然不匹配 FF<TT>),因此特化匹配。
    print(r);                 // ok, prints "template"

推导得出以下结果:1个匹配项,带有 T = R<int>。对于2, R<int>FF<TT>模式匹配,因此它是可行的,并带有 FF = RTT = int。 3,像往常一样,不知道该如何处理 T2。重载解析获得1和2(同一性)的相同序列,因此部分功能模板排序解决了歧义:2比1更专业,因此被选择。
    print<int,int>(1);        // ok, prints "two type parameters"

两个显式类型模板参数。 1只接受一个。 2需要一个模板作为第一个参数。剩下3个。
    print<R<int>,int>(r);     // ok, prints "two type parameters"

这与先前的情况相同。第一个参数是 R<int>而不是 int,但这仍然只是一个类型,而2不喜欢它。
    print<R<int> >(r);        // (1) ?? why "simple" ??

这与第一种和第三种情况相同。我们有一个显式类型模板参数。 3无法推断 T2,2要以模板作为第一个参数,因此1是唯一选择。 R<int>是一种类型,而不是模板。
    print<R,int >(r);         // (2) ?? prints "template",

在这里,我们有两个显式的模板参数,第一个是模板,第二个是类型。 1仅接受一个参数。 3要为其第一个模板参数指定类型。 2很高兴将模板作为第一个参数,将类型作为第二个参数。

这里的主要类(class)是:
  • 在进行任何演绎或重载解析之前,将显式模板参数与模板参数进行匹配,因此首先仅匹配某些函数。
  • 1和2是重载,它们的重载解决方案分开发生。如果2是1的特化,那会有所不同,但是不存在部分功能模板的特化。
  • 除非您为其提供参数,否则它只是一个模板。实例化的功能模板是一个功能。实例化的类模板是一个类(因此是一个类型)。类模板的实例化和非模板类的实例化之间没有区别,除了参数推论和部分特化所进行的模式匹配之外。

  • 编辑:回答扩展问题。

    When I replace function overloading with template specialization, then template pattern matching works as I would have expected. I have some trouble believing that the pattern matching rules also differ between classes and functions.



    这是一个观点问题。类和函数没有模式匹配规则,因此您不能说它们有所不同。有用于部分特化和模板自变量推导的模式匹配规则。这些实际上是相同的。部分特化(14.5.5)部分指的是函数模板参数推导(14.8.2)部分。

    因此,模式匹配规则是相同的。

    但是,参数推导仅适用于函数(至少尚未针对类模板进行参数推导),而部分专用化仅适用于类(不能对函数进行部分专用化)。这是函数和类之间的主要区别:在第一个示例中,您有两个函数模板:
    template <typename T> void print(T i);
    template <template <typename> class FF, typename TT> void print(FF<TT> i);

    这是两个不同的模板。他们是完全独立的。取决于复杂的规则以及显式参数传递,参数推导和重载解析的相互作用,以确定在任何给定调用中意味着哪个。但是,这很重要,彼此之间可以互不存在。换句话说,假设您只有一个功能:
    template <template <typename> class FF, typename TT> void something_else(FF<TT> i);

    然后,您会惊讶 something_else<R, int>(r);是有效的吗?您有一个带有两个参数的模板,并且传递了两个参数。仅有一个参数的另一个模板的存在不会改变这一点!

    这很重要,因此我重复一遍:两个功能模板(即使它们具有相同的名称)是完全独立的模板。

    类不是这样。如果您对类尝试相同的操作,则编译器会抱怨:
    template <typename T> class Q {};
    template <template <typename> class FF, typename TT> class Q {};

    lang声:
    redef.cc:2:5: error: too many template parameters in template redeclaration

    您不能有两个具有相同名称的类模板。编译器认为您想再次声明旧的 Q,并抱怨模板参数列表不匹配。

    您可以对类模板进行的唯一操作就是对它们进行专用化,就像在第二个示例中所做的那样:
    template <typename T> class P {};
    template <template <typename> class FF, typename TT> class P<FF<TT>> {};

    但是请注意,这些不是独立的模板。他们甚至不是同一件事。第一个是类模板,而第二个是类模板部分特化。第二个完全依赖第一个。删除主模板意味着该特化不再编译:
    redef.cc:2:64: error: explicit specialization of non-template class 'P'    

    与重载的功能模板不同,类模板的部分特化不是用户可以引用的实体。对于用户,只有一个模板 P,并且它具有一个模板参数。如果此参数采用特定形式,则特化将匹配,但是与第一个示例中的第二个功能模板不同,该特化不是具有两个参数的独立模板。

    这就是 P<R<int>>::print(r)可以编译和起作用的原因: P具有一个参数,并为其传递了 R<int>。部分特化匹配模式,因此被选择。但是 P<R, int>::print(r)不起作用: P仅具有一个模板参数,在这里您尝试传递两个。特化不是它自己的实体,因此不被考虑。

    但是功能模板都是独立的完整模板。只有完整的特化 template <> void print<int>(int i)不是。

    所以总结一下:
  • 函数模板可以完全专用或重载。重载的函数模板是完全独立的:当您想知道可以或应该显式提供哪些参数时,请依次查看其所有参数列表。
  • 避免专用于功能模板。它以怪异的方式与重载的函数模板进行交互,最终您可能会得到与预期调用不同的函数。只是重载功能模板,以及其他功能模板和简单函数。局部排序规则很直观;只要记住,如果有疑问,会在模板上选择一个普通函数。
  • 类模板可以完全或部分专用,但不能重载。专业不是独立的模板;实例化类模板时,始终必须转到参数列表的主模板。
  • 用于选择部分特化和从函数参数推导出模板参数的匹配规则是相同的。但是,当您将模板参数显式传递给功能模板时,不会对这些参数执行推论。
  • 关于c++ - 函数重载匹配模板template,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18565509/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com