为什么这段代码不能编译?
#include <iostream>
#include <vector>
template<class T>
class vector_ref
{
public:
vector_ref(T *pData, int pN) {Data = pData; N = pN;};
T *Data;
int N;
vector_ref<T>& operator=(const std::vector<T> &v1)
{
for(int ii = 0; ii < N; ii++)
{
Data[ii] = v1[ii];
}
return *this;
};
operator std::vector<T>()
{
std::vector<T> v1(N);
for(int ii = 0; ii < N; ii++)
{
v1[ii] = Data[ii];
}
return v1;
};
};
template<class T>
void printVec(std::vector<T> v1)
{
for(int ii = 0; ii < v1.size(); ii++)
{
std::cout << v1[ii] << std::endl;
}
}
int main()
{
std::vector<double> v;
v.push_back(1.0);
v.push_back(2.0);
v.push_back(3.0);
vector_ref<double> v_ref(&v[0],3);
printVec(v_ref); // Compiler error
return 0;
}
我使用命令g++ 4.7.3
编译g++ test.cpp
。错误消息是:
test.cpp: In function ‘int main()’:
test.cpp:56:19: error: no matching function for call to ‘printVec(vector_ref<double>&)’
test.cpp:56:19: note: candidate is:
test.cpp:40:6: note: template<class T> void printVec(std::vector<T>)
test.cpp:40:6: note: template argument deduction/substitution failed:
test.cpp:56:19: note: ‘vector_ref<double>’ is not derived from ‘std::vector<T>’
前一个问题answer似乎表明这应该有效。
答案 0 :(得分:2)
正如错误消息所示:
test.cpp:56:19: error: no matching function for call to ‘printVec(vector_ref<double>&)’
果然,那条线是:
vector_ref<double> v_ref(&v[0],3);
printVec(v_ref); // Compiler error
请注意,v_ref
是vector_ref<double>
。现在,错误消息有助于指出存在printVec
函数,但它有所不同:
test.cpp:56:19: note: candidate is:
test.cpp:40:6: note: template<class T> void printVec(std::vector<T>)
如果我们转到第40行并查看printVec函数,您将看到:
template<class T>
void printVec(std::vector<T> v1)
所以,这就是这个意思:
std::vector<T>
为参数。vector_ref<double>
作为参数调用它。这就是错误信息的含义。
现在,我看到你正试图制作一些可以隐式转换为矢量的东西。由于模板,这会变得混乱。这种方法适用于包装非模板类型,但是模板有问题,这就是原因:
当编译器试图处理printVec(v_ref)
时,它必须找到这样的printVec
的声明。它寻找需要vector_ref<double>
的东西,却找不到任何东西。它确实找到了一个模板函数,因此它会尝试查看是否可以为此类型实例化模板函数。 printVec
的签名是std::vector<T>
,与vector_ref<double>
不匹配,因此它不匹配,并继续前进。它真的很简单,“不匹配,放弃,继续前进”。它不会尝试对您的类型进行任何转换。
要解决此问题,您可以添加一个明确的.toVector()
,如塞巴斯蒂安建议的那样。或者,它可能会显式实例化模板方法:
template<class T>
void printVec(std::vector<T> v1)
{
for(int ii = 0; ii < v1.size(); ii++)
{
std::cout << v1[ii] << std::endl;
}
}
template<> void printVec(std::vector<double> v1); // explicit instantiation
明确告诉编译器为std::vector<double>
实例化模板方法,然后当它试图找到printVec(vector_ref<double>)
的匹配时,它会看到两个选项 - 模板方法和实例化方法。模板方法将像以前一样失败,但它可能意识到它可以执行隐式转换以使用实例化方法。这个可能有效,但我还没有测试过。
我不确定这是否有效,.toVector()
肯定更清洁。但显式模板实例化是一个巧妙的技巧,偶尔也有用,所以我想我会提到它。
答案 1 :(得分:1)
你隐式转换为vector&amp;是不安全的,会做可怕的事情。去掉它。并打开你的编译器警告,因为编译器应该已经为你尖叫了。
编译器错误背后的问题是参数推断不会将转换考虑在内;它在参数类型和参数类型模式之间进行严格的模式匹配。 vector<T>
和vector_ref<double>
之间不匹配。
你无法让这条线路运转起来。向vector_ref
提供向量的完整界面并使printVec
成为完整模板,或使用显式强制转换或显式转换函数,例如: v_ref.to_vector()
。
答案 2 :(得分:1)
见Sebastian Redl&amp; Tim回答了为什么编译失败
您可以重载()
:与Sebastian Redl建议的to_vector
功能相似
std::vector<T> operator() ()
{
std::vector<T> v1(N);
for(int ii = 0; ii < N; ii++)
{
v1[ii] = Data[ii];
}
return v1;
}
然后使用
printVec(v_ref());
参见 here