Why does this code not compile?
#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;
}
I am compiling with g++ 4.7.3
using the command: g++ test.cpp
. The error message is:
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>’
This answer to a previous question seems to suggest that this should work.
As the error message says:
Sure enough, that line is:
Note that
v_ref
is avector_ref<double>
. Now, the error message helpfully points out that there is aprintVec
function, but it's different:And if we go to line 40 and look at the printVec function, you will see:
So, here's what this means:
std::vector<T>
as an argument.vector_ref<double>
as an argument.So that's what the error message means.
Now, I see that you're trying to make something that can be implicitly converted to a vector. This gets messy because of the templates. This approach works for wrapping non-template types, but has trouble with templates, and here's why:
When the compiler is trying to deal with
printVec(v_ref)
, it has to find the declaration for such aprintVec
. It looks for something that takesvector_ref<double>
, but doesn't find anything. It does find a template function, so then it tries to see if the template function can be instantiated for this type. The signature forprintVec
is that it takesstd::vector<T>
, and that doesn't matchvector_ref<double>
, so it doesn't match, and it moves on. It really is as simple as "doesn't match, give up and move on". It won't try to do any conversions on your type.To solve this, you can add an explicit
.toVector()
as Sebastian suggests. Or, it might work to explicitly instantiate the template method:That explicitly tells the compiler to instantiate the template method for
std::vector<double>
, and then when it's trying to find a match forprintVec(vector_ref<double>)
, it will see two options - a template method and an instantiated method. The template method will fail as before, but it might realize that it can do an implicit conversion to use the instantiated method. This might work, but I haven't tested it.I'm not sure if that will work, and
.toVector()
is definitely cleaner. But explicit template instantiation is a neat trick, and occasionally useful, so I thought I'd mention it.