Мне нужна функция, которая может принимать в качестве аргумента либо valarray, либо вектор. Приведенный ниже (тривиальный пример) код отлично работает на C++17 (компилируется, запускается и дает правильный ответ), но не может скомпилироваться на C++20 с сообщением об ошибке.
«GetSum»: не найдена соответствующая перегруженная функция.
Это работает, если я вызываю версию указателя напрямую, но, очевидно, будет удобнее, если я смогу просто передать контейнер.
template<class T>
T GetSum(std::valarray<T>& vIn)
{
return GetSum(&vIn[0], vIn.size());
}
template<class T>
T GetSum(std::vector<T>& vIn)
{
return GetSum(&vIn[0], vIn.size()); // could use .data() here
}
// pointer version
template<class T>
T GetSum(T* vIn, size_t n)
{
T sum{};
for (size_t i = 0; i < n; ++i)
sum += vIn[i];
return sum;
}
void OnTest()
{
std::vector<double> vec(10, 1);
std::valarray<int> val(3, 10);
double x = GetSum(vec);
int i = GetSum(val);
...
Извините за мое невежество, но может кто-нибудь сказать мне, что я делаю неправильно? (К вашему сведению, я задал вопрос по этой теме некоторое время назад, и именно поэтому я заставил код C++17 работать нормально, но теперь я пытаюсь перейти на C++20 и обнаруживаю, что мой код больше не работает).
Просто переместите версию указателя перед двумя другими версиями. См. рабочую демонстрацию По сути, вы вызываете версию указателя перед ее объявлением.





может кто-нибудь сказать мне, что я делаю неправильно?
Проблема в том, что вы пытаетесь вызвать указательную версию GetSum перед ее объявлением. Другими словами, когда вы написали GetSum(&vIn[0], vIn.size()), компилятор не может найти подходящую версию, поскольку поиск по имени учитывает объявление только в этой точке или до нее.
Чтобы решить эту проблему, вы можете переместить его объявление перед его использованием/вызовом, как показано ниже:
//first declare/define this
template<class T>
T GetSum(T* vIn, size_t n)
{
T sum{};
for (size_t i = 0; i < n; ++i)
sum += vIn[i];
return sum;
}
//now you can use the above
template<class T>
T GetSum(std::vector<T>& vIn)
{
//now this'll work because we've already declared the pointer version above
return GetSum(&vIn[0], vIn.size());
}
template<class T>
T GetSum(std::valarray<T>& vIn)
{
return GetSum(&vIn[0], vIn.size());
}
Спасибо за сверхбыстрое решение. Но с какой стати до этого все работало нормально в C++17 (и 14)? Это новое ограничение в C++20? Или мне просто повезло с глюком компилятора в предыдущей версии??
@BillHeitler Это также не работает в C++17. Смотрите демо . Пожалуйста.
Что ж, честно говоря, за последние несколько лет код компилировался и запускался в Visual Studio, включая VS2022, сначала с настройками C++14, а затем с настройками C++17. Проблема стала очевидной только когда я перешел на C++20. Я не знаю, были ли в более ранних версиях MS какие-то обходные пути, или мне просто повезло, что необнаруженное неопределенное поведение дало правильный ответ. Но я благодарен за ваше решение (которое, безусловно, имеет смысл), и буду искать его в будущем.
@BillHeitler Я думаю, что вы, возможно, не компилируете свой код на C++17 с флагом /permissive-. Этот флаг автоматически используется в C++20. В то время как в C++17 и C++14 вы должны использовать его явно, записывая /permissive-. Обратите внимание на - в конце флага. Попробуйте скомпилировать свою программу с этим флагом и C++17 или C++14, и вы заметите, что msvc отклонит ее. Посмотрите демо и вы заметите, что это действительно так. Поэтому, как правило, всегда компилируйте программу msvc с флагом /permissive-.
Ты совершенно прав. В обеих версиях флаг соответствия был установлен на Default, но я не заметил, что значение по умолчанию изменилось в C++20! Это объясняет довольно много изменений кода, которые мне пришлось внести при переходе на C++20. Спасибо за ваше время и труд, ответив на этот вопрос.
пожалуйста, включите минимальный воспроизводимый пример и полное сообщение об ошибке в вопрос