c++ 在函数中使用算法导致错误:没有重载函数的示例

w8rqjzmb  于 2022-11-27  发布在  其他
关注(0)|答案(1)|浏览(368)

我在函数中尝试使用算法。
应该很简单。
但是,无论我尝试使用哪种算法,当在函数中使用时,它们都会导致相同的错误。
E0304重载函数“std::开始”没有与参数列表匹配的示例
E0304没有重载函数“std::end”的示例与参数列表匹配
我猜有一些小的变化,需要作出。

#include <iostream>
#include <algorithm>

#include "bool_element_option_03.h"
#include "storage.h"

int main()
{
    int arr_value[ELEMENTS]{ 1, 2, 9, 4, 5, 6, 7, 8 };

    int arr_copy_value[ELEMENTS];
    
    // array population
    for (int var_create_array_a = 0; var_create_array_a < ELEMENTS; var_create_array_a++)
    {
        arr_copy_value[var_create_array_a] = 0;
    }

    //std::copy(std::begin(arr_value), std::end(arr_value), std::begin(arr_copy_value));
    //std::sort(std::rbegin(arr_copy_value), std::rend(arr_copy_value));

    for (int output = 0; output < ELEMENTS; output++)
    {
        std::cout << "copied decimals: " << arr_copy_value[output] << std::endl;
    }

    bool_element_option_03(arr_value, arr_copy_value);

    return 0;
}

//-——————————————————————————————————————————————————————————————-

#ifndef _STORAGE_H
#define _STORAGE_H
#define WIN32_LEAN_AND_MEAN

// -----------------------------------------------------------------------------------------------------------------------------------------------------
//                  Constants
// -----------------------------------------------------------------------------------------------------------------------------------------------------

//-----------------------------------------------
const int ELEMENTS = 8;
//-----------------------------------------------

#endif

//-——————————————————————————————————————————————————————————————-

#include <iostream>
#include <algorithm>

#include "storage.h"

void bool_element_option_03(int arr_value[], int* arr_copy_value)
{
    std::copy(std::begin(arr_value + ELEMENTS), std::end(arr_value + ELEMENTS), std::begin(arr_copy_value + ELEMENTS));
    std::sort(std::rbegin(arr_copy_value + ELEMENTS), std::rend(arr_copy_value + ELEMENTS));

    for (int output = 0; output < ELEMENTS; output++)
    {
        std::cout << "copied decimals: " << arr_copy_value[output] << std::endl;
    }
}

如果我把这些算法从函数中取出并放在main()中,它们就可以正常工作。
我是否应该故意重载这个函数(以便在其中使用算法)?
重载这个函数不是我的意图。我不会用不同的参数多次调用它。这个函数只被调用一次。
编辑:* 最小可重现示例 *

0lvr5msh

0lvr5msh1#

错误文本是明确的:
E0304重载函数“std::开始”没有与参数列表匹配的示例
那么,这些示例是什么呢?参见例如https://en.cppreference.com/w/cpp/iterator/begin

template< class C >
constexpr auto begin( C& c ) -> decltype(c.begin());   

template< class C >
constexpr auto begin( const C& c ) -> decltype(c.begin());

精确返回c.begin(),它通常是c所表示的序列开头的迭代器。如果C是标准的 Container,则当c不是常量限定时,返回C::iterator,否则返回C::const_iterator

template< class T, std::size_t N >
constexpr T* begin( T (&array)[N] ) noexcept;

返回指向数组开头的指针。
最后一个看起来很有前途,它的参数是对数组的引用(注意它是如何声明的),这就是这里使用的重载:

int main()
{
    int arr_value[ELEMENTS]{ 1, 2, 9, 4, 5, 6, 7, 8 };
    int arr_copy_value[ELEMENTS];
    
    // ...
    
    std::copy(std::begin(arr_value),       // <---
              std::end(arr_value),
              std::begin(arr_copy_value)); // <---     
    // ...
}

这是因为arr_valuearr_copy_value都是数组。
另一方面,当编译器读取重构后的代码时,它找不到合适的重载:

void bool_element_option_03(int arr_value[], int* arr_copy_value)
{   //                                   ^^ That's kind of misleading
    std::copy(std::begin(arr_value + ELEMENTS),
              std::end(arr_value + ELEMENTS),
              std::begin(arr_copy_value + ELEMENTS));
    // ...
}

这里,arr_valuearr_copy_values都是 * 指针 *,而不是数组,并且在标准库中没有接受 * 指针 * 的std::begin()(以及类似的)重载。
给定main中的调用bool_element_option_03(arr_value, arr_copy_value);,由于数组到指针衰减(1),它们分别指向main中声明的两个数组的第一个元素。它们是局部变量,碰巧与main中的变量同名。
此外,arr_value + ELEMENTS指向数组最后一个元素的后面一个元素,只要它没有被解引用,它就是一个有效的指针。
通过直接将这些指针(2)传递给SL算法函数,可以在不更改调用位置的情况下使此函数工作:

void bool_element_option_03(int const *arr_value, int *arr_copy_value)
{
    std::copy(arr_value, arr_value + ELEMENTS, arr_copy_value);
    std::sort(arr_copy_value, arr_copy_value + ELEMENTS, std::greater{});
    // ...
}

这也可以通过传递大小来推广:

void bool_element_option_03( size_t n, int const *src, int *dest)
{ //                         ^^^^^^^^ 
  std::copy(src, src + n, dest);
  std::sort(dest, dest + n, std::greater{});
  // ...
}

为了进一步推广,可以将函数签名修改为接受数组引用的模板:

template< class Type, std::size_t N>
void bool_element_option_03(Type const (&arr_value)[N], Type (&arr_copy_value)[N])
{
    std::copy(std::begin(arr_value), std::end(arr_value), 
              std::begin(arr_copy_value));
    std::sort(std::rbegin(arr_copy_value), std::rend(arr_copy_value));
    // ...
}

它仍然可以在main中用bool_element_option_03(arr_value, arr_copy_value);调用,只是现在没有衰减,数组实际上是通过引用传递的,可以选择正确的std::begin重载。
为了模仿标准库算法,我们可以直接传递迭代器:

template< class SourceRandomIterator, class DestRandomIterator >
void copy_and_sort( SourceRandomIterator source_first
                  , SourceRandomIterator source_last
                  , DestRandomIterator dest_first )
{
    auto dest_last{ std::copy(source_first, source_last, dest_first) };
    std::sort(dest_first, dest_last, std::greater{});
    // ...
}

但是我们还必须修改main中的调用:

bool_element_option_03(std::cbegin(arr_value), std::cend(arr_value), 
                       std::begin(arr_copy_value));

从C++20开始,我们可以使用std::span作为参数。

void bool_element_option_03(std::span<const int> arr_value,
                            std::span<int> arr_copy_value)
{
    std::copy(std::begin(arr_value), std::end(arr_value), 
              std::begin(arr_copy_value));
    std::sort(std::rbegin(arr_copy_value), std::rend(arr_copy_value));
    // ...
}

或者利用ranges library

template< std::ranges::random_access_range SourceRange
        , std::ranges::random_access_range DestRange >
void bool_element_option_03(SourceRange const& source,
                            DestRange& dest)
{
    std::ranges::copy(source, dest);
    std::ranges::sort(dest | std::ranges::views::reverse );
    // ...
}

在这两种情况下,都可以从main调用此函数,调用方式为bool_element_option_03(arr_value, arr_copy_value);
1)What is array to pointer decay?
2)例如,请参阅How are iterators and pointers related?以及std::sort是如何宣告的。

相关问题