转换运算符不适用于函数参数

时间:2013-09-05 16:21:04

标签: c++ implicit-conversion conversion-operator

为什么这段代码不能编译?

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

3 个答案:

答案 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_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)

所以,这就是这个意思:

  1. printVec以std::vector<T>为参数。
  2. 你用vector_ref<double>作为参数调用它。
  3. 这些是完全不同的类型,所以它失败了。
  4. 这就是错误信息的含义。

    现在,我看到你正试图制作一些可以隐式转换为矢量的东西。由于模板,这会变得混乱。这种方法适用于包装非模板类型,但是模板有问题,这就是原因:

    当编译器试图处理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