函数特化/重载规则示例

时间:2017-01-11 15:04:55

标签: c++ templates overloading template-specialization overload-resolution

我知道你不能部分专门化一个函数模板,我也理解典型的函数重载。

我需要帮助的地方是了解下面4个foo()函数之间的区别。我希望它们中的一些是完全相同的不同语法?

对于每个函数,是否有人能够更好地解释究竟发生了什么?它是模板特化还是重载,以及c ++编译器如何确定要调用的内容?

//(1)
template<typename T>
void foo(T t)
{
    cout << "template<T> foo(T) " << endl;
}

//(2)
template<>
void foo<int*>(int* l)
{
    cout << "template<> foo<int*>(int*) " << endl;
}

//(3)
template<typename T>
void foo(T* l)
{
    cout << "template<T> foo(T*) " << endl;
}

//(4)
void foo(int* l)
{
    cout << "normal overload foo(int*) " << endl;
}

int main()
{
    int x = 0;
    foo(x);
    foo(&x);
    return 0;
}

节目输出:

template<T> foo(T)
normal overload foo(int*)

4 个答案:

答案 0 :(得分:5)

评论中的解释:

// the 1st primary function template, overloaded function template
template<typename T>
void foo(T t)

// full template specialization of the 1st function template with T = int*
template<>
void foo<int*>(int* l)

// the 2nd primary function template, overloaded function template
template<typename T>
void foo(T* l)

// non-template function, overloaded function
void foo(int* l)

int main()
{
    int x = 0;
    foo(x);  // only match the 1st function template; the others take pointer as parameter
    foo(&x); // call the non-template function, which is prior to templates in overload resolution
    return 0;
}

详细了解overload resolutionexplicit (full) template specialization

答案 1 :(得分:1)

让我们通过第一个电话foo(x)

int不能写为指针,无法推断参数,下一步

void foo(int* l);

无法隐式地将int转换为int*

template<typename T>
void foo(T t);

这似乎是一个很好的匹配,就像记住它2)。下一步

template<>
void foo<int*>(int* l);

无法隐式地将int转换为int*

template<typename T>
void foo(T* l)

因此,唯一可能的匹配是2),因此template<T> foo(T)是输出。

第二个电话,foo(&x)

void foo(int* l);

非模板函数,它完全匹配x的类型。让我们记住这个。

template<typename T>
void foo(T t);

很好的比赛!但前一个仍然更好,接下来

template<>
void foo<int*>(int* l);

哦,上一个模板的特殊化与该类型完全匹配,更好,但1)仍然是更好的匹配。下一步

template<typename T>
void foo(T* l)

比专业化更好,模板没有,但没有击败非模板。

最后,调用非模板函数。非模板总是比模板更好。

答案 2 :(得分:0)

foo(x)的分辨率很容易发现,因为除了template<typename T> void foo(T t)之外没有其他候选函数。

所以我们的问题会缩小为:void foo(int* l)拨打foo(&x)为何?

  1. 调用模板方法template<> void foo<int*>(int* l) ,您需要致电foo<int*>(&x)
  2. template<typename T> void foo(T* l)致电foo<int>(&x)
  3. template<typename T> void foo(T t)致电foo<int*>(&x)
  4. 正如您所看到的,调用foo(&x)与上述三种使用显式模板调用的任何风格都不匹配。

    请注意,如果没有专门的函数void foo(int* l),函数调用foo<int*>(&x)将由专门的模板函数 template<> void foo<int*>(int* l)解决非专业化模板功能 template<typename T> void foo(T t)

答案 3 :(得分:0)

在尝试确定重载时调用的函数时,规则是:始终找到需要使用最少优化的函数。

当用int调用foo()时,唯一可以使用的函数是第一个,因为你不能将int转换为int *。

与int *:
一起使用时 功能4可以在没有任何优化的情况下使用 函数3需要改变T-> int以便运行 函数1需要将T更改为指针类型,并确定T指向int 功能2是功能1的专业化

所以函数4可以立即使用,函数2需要更新模板类型,函数1,2需要更新模板类型和对象类型。
所以按顺序调用它们:4然后3然后2然后1