为什么此代码无法编译?

#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似乎表明这应该可行。

最佳答案

如错误消息所述:

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_refvector_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)

因此,这意味着什么:
  • printVec使用std::vector<T>作为参数。
  • 您以vector_ref<double>作为参数来调用它。
  • 这些是完全不同的类型,因此失败。

  • 这就是错误消息的含义。

    现在,我看到您正在尝试制作可以隐式转换为 vector 的内容。由于模板,这变得凌乱。这种方法适用于包装非模板类型,但是在使用模板时遇到了麻烦,原因如下:

    当编译器尝试处理printVec(v_ref)时,它必须找到此类printVec的声明。它寻找需要vector_ref<double>的东西,但是什么也没找到。它确实找到了模板函数,因此它尝试查看是否可以为该类型实例化模板函数。 printVec的签名是std::vector<T>,并且不匹配vector_ref<double>,所以不匹配,然后继续前进。真的很简单,就是“不匹配,放弃并继续前进”。它不会尝试对您的类型进行任何转换。

    为了解决这个问题,您可以按照Sebastian的建议添加一个显式的.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()绝对更干净。但是显式模板实例化是一个巧妙的窍门,有时很有用,所以我想提到它。

    09-11 17:32