Оператор преобразования не работает для параметра функции

Почему этот код не компилируется?

#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>’

это ответ предыдущий вопрос, кажется, предполагает, что это должно работать.

1

Решение

Как говорится в сообщении об ошибке:

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)

Итак, вот что это значит:

  1. printVec занимает std::vector<T> в качестве аргумента.
  2. Вы называете это с vector_ref<double> в качестве аргумента.
  3. Это совершенно разные типы, так что не получается.

Вот что означает сообщение об ошибке.

Теперь я вижу, что вы пытаетесь создать что-то, что может быть неявно преобразовано в вектор. Это становится грязным из-за шаблонов. Этот подход работает для упаковки не шаблонных типов, но имеет проблемы с шаблонами, и вот почему:

Когда компилятор пытается разобраться с 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() определенно чище. Но явная реализация шаблона — это хитрый трюк, а иногда и полезный, поэтому я решил упомянуть об этом.

2

Другие решения

Ваше неявное преобразование в вектор& небезопасно и будет делать ужасные вещи. Убери это. И включите предупреждения вашего компилятора, потому что компилятор уже должен был кричать на вас.

Проблема вашей ошибки компилятора в том, что при выводе аргументов не учитываются преобразования; он выполняет строгое сопоставление с образцом между типом аргумента и шаблоном типа параметра. И нет никакого совпадения между vector<T> а также vector_ref<double>,

Вы не можете заставить эту линию работать. Либо дать vector_ref полный интерфейс вектора и сделать printVec полный шаблон или использовать явное приведение или явную функцию преобразования, например, v_ref.to_vector(),

1

Смотри Себастьян Редл & Тим отвечает за то, почему не удалось скомпилировать


Вы можете перегрузить (): похожий на 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());

Увидеть Вот

1