没有与指定类型匹配的 重载函数 "maxn" 实例

template <typename T>
auto maxn(const T arr[])->T
{
    int len=sizeof(arr) / sizeof(arr[0]);
    T m=arr[0];
    for (int i = 1; i < len; i++)
    {
        if (m<arr[i])
        {
            m=arr[i];
        }
    }
    return m;
}

template <> char* maxn <char*>(const char* arr[])
{
    return arr[0];
}

template <typename T>
auto a(T q,T w)->T
{
    cout<<(q+w);
    return q;
}

 

顺便一提,由于处理指针指向的数组的需求非常常见,而这种情况下不可能获取数组长度,我们通常会这么写:

#include <iostream>
#include <numeric>

template <typename T>
T maxn(size_t sz, T* para) {
	T maxn = std::numeric_limits<T>::min();
	for (size_t i = 0; i < sz; ++i) {
		maxn = maxn > para[i] ? maxn : para[i];
	}
	return maxn;
}

int main() {
	int a[] = {1, 5, 3, 4, 2};
	int *p = new int[5];
	p[0] = 4; p[1] = 2; p[2] = 3; p[3] = 1; p[4] = 5;
	std::cout << "maxn: " << maxn(sizeof(a) / sizeof(int), a) << std::endl;
	std::cout << "maxn: " << maxn(5, p) << std::endl;
	delete[] p;
	return 0;
}

这时,调用参数的正确性由调用者而不是被调用者来保证。(毕竟也没有更通用的办法。)

这个报错主要跟调用处有关,只凭借函数/函数模板的定义无法准确定位问题。方便的话请把调用处代码也贴上来 。

顺便一提,这段代码看起来不能传递int*类和类似的指针参数(int*和int[]是完全不同的数据类型)。如果希望能对malloc分配获得的“数组”进行操作,还需要有指针形参的模板重载。

#include <iostream>
using namespace std;

template <typename T>
auto maxn(T arr[4])-> decltype(arr[0]);

int main()
{
    int a[4]={1,2,3,5};
    cout<<maxn(a);
    return 0;
}

template <typename T>
auto maxn(T & arr)-> decltype(arr[0])
{
    int len = sizeof(arr) / sizeof(arr[0]);
    decltype(arr[0]) m=arr[0];
    for (int i = 1; i < len; i++)
    {
        if (m<arr[i])
        {
            m=arr[i];
        }
    }
    return m;
}

这是我目前的想法

然后下面是报错

undefined 
reference to `decltype ({parm#1}[0]) maxn<int>(int*)'
collect2.exe: error: ld returned 1 exit status

但是,如下运行则没错

int main()
{
    int a[4]={1,2,3,5};
    maxn(a);
    return 0;
}

template <typename T>
void maxn(T & arr)
{
    int len = sizeof(arr) / sizeof(arr[0]);
    decltype(arr[0]) m=arr[0];
    for (int i = 1; i < len; i++)
    {
        if (m<arr[i])
        {
            m=arr[i];
        }
    }
    cout<<m;
}

其中T的类型是int [4],我是用下面这个函数获取的

template <class T>
int getArrayLen(T & array)
{
    //cout<<typeid(T).name()<<"\n";
    cout<<abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr)<<"\n";
    return (sizeof(array) / sizeof(array[0]));
}

困惑

第二种做法没出问题应该是容易理解的,先解释原始代码为啥报错。

答案其实异常简单:你的函数模板声明为T[4]类型,定义却只有T&类型的,你的声明在编译阶段没出现问题,却无法链接,就是因为声明和定义对不上;你原始代码的声明和定义是重载,而不是对声明过的模板的定义。换言之,它们是两个模板,而不是同一个。编译时,编译器只处理了后一个(只有声明没有定义的话,寻找全局定义是链接器的工作,与编译器无关),而前一个只保留了调用接口却没有实现。链接时,链接器找不到对应的实现,当然就会报错了。

这里提供一段能工作的代码:

#include <iostream>
#include <numeric>

template <typename T, size_t sz>
T maxn1(const T (&para)[sz]) {
	T maxn = std::numeric_limits<T>::min();
	for (size_t i = 0; i < sz; ++i) {
		maxn = maxn > para[i] ? maxn : para[i];
	}
	return maxn;
}

template <typename T, size_t sz>
T maxn2(const T (&para)[sz]) {
	T maxn = std::numeric_limits<T>::min();
	for (const T& val : para) {
		maxn = maxn > val ? maxn : val;
	}
	return maxn;
}

int main() {
	int a[] = {1, 5, 3, 4, 2};
	std::cout << "maxn1: " << maxn1(a) << std::endl;
	std::cout << "maxn2: " << maxn2(a) << std::endl;
	return 0;
}

 

感谢