gpt4 book ai didi

c++ - 如何使用 C++ 中的平凡仿函数避免 "invalid initialization of reference"错误

转载 作者:太空宇宙 更新时间:2023-11-04 12:36:30 25 4
gpt4 key购买 nike

我有一个“功能迭代器”类型的类——也就是说,迭代器返回的值首先由一个函数对象处理,它是模板参数。此模板参数的默认值为“平凡仿函数”,它只返回它收到的参数。

当我添加 const 成员函数时出现问题,该成员函数应返回对元素的 const 引用。为简单起见,假设我们有一个“前向迭代器”并希望有一个函数“peek_next”,它允许查看下一个元素,但不能更改它。这是我的看法(这是最小的可编译示例):

#include <functional>
#include <iostream>
#include <vector>
/**
* This is an empty functor which just returns back its argument.
*/
template <class T>
class basic_functor: public std::unary_function<T, T>
{
public:
typedef basic_functor self;
basic_functor()
{}

/**
* Returns back the argument passed to it. const version
*/
inline const T& operator()(const T& arg) const
{ return arg; }

/**
* Returns back the argument passed to it.
*/
inline T& operator()(T& arg)
{ return arg; }

};// class basic_functor

/**
* @param S type of the elements.
* @param BaseIterator type of the iterator it builds upon.
* @param functor which is applied to the element to which iterator points.
* by default it is empty functor -- the element itself is returned.
*/
template <typename S,
typename BaseIterator,
typename Functor=basic_functor<S> >
class iterator_functional:
public std::iterator<std::forward_iterator_tag,
typename Functor::result_type >
{
public:
///type defining itself
typedef iterator_functional self;
///type of the functor
typedef Functor functor_type;
///type of linear iterator
typedef BaseIterator base_iterator_type;
///type for rebinding the iterator with another functor
template <typename F>
struct rebind
{
typedef iterator_functional<S, base_iterator_type, F> other;
};

/**
* Constructor.
*/
iterator_functional(base_iterator_type it,
functor_type funct = functor_type()):
m_it(it),
m_functor(funct)
{
}

/**
* Copying constructor.
* @param other source of the data.
*/
iterator_functional(const self&other):
m_it(other.m_it),
m_functor(other.m_functor)
{ }

/**
* Provides access to element to which iterator points.
* @return element to which iterator points to.
*/
inline typename self::reference operator*()
{ return m_functor(*m_it); }

/**
* Provides access to element to which iterator points.
* @return element to which iterator points to.
*/
inline const typename self::reference operator*() const
{ return m_functor(*m_it); }
// Will work only when the code below is 'unlocked'
#if 0
/**
* Returns reference to the next element.
*/
inline typename self::reference peek_next()
{
auto temp_it = m_it;
++temp_it;
return
m_functor(*temp_it);
}//iterator_type_const
#endif

/**
* Returns reference to the next element.
*/
inline const typename self::reference peek_next() const
{
auto temp_it = m_it;
++temp_it;
return
m_functor(*temp_it);
}//iterator_type_const

private:
base_iterator_type m_it;
functor_type m_functor;
};//iterator_functional;

typedef std::vector<int>::iterator v_int_iterator;
typedef std::vector<int>::const_iterator v_int_const_iterator;

typedef iterator_functional<int, v_int_iterator> iterator_type;
typedef iterator_functional<const int, v_int_const_iterator> iterator_type_const;

int main()
{
std::vector<int> vec_1({1, 2, 3, 4});
const std::vector<int> vec_2({5, 6, 7, 8});

iterator_type it(vec_1.begin());
std::cout << " *it =" << *it << "; it.peek_next() = " << it.peek_next() << std::endl;

iterator_type_const cit(vec_2.begin());
std::cout << "*cit =" << *cit << "; cit.peek_next() = " << cit.peek_next() << std::endl;
return 0;
}

问题是要编译此示例,我必须允许非 const 版本的 peek_element 函数。否则编译器失败并显示消息

error: invalid initialization of reference of type 'std::iterator<std::forward_iterator_tag, int, long int, int*, int&>::reference {aka int&}' from expression of type 'const int'

据我所知,编译器使用 basic_functor::operator() 的非常量版本。

那么我该如何避免呢?是的,我知道 unary_function 已从 C++17 中删除。

最佳答案

好的,感谢评论中的讨论(@danadam 和@DavisHerring),我找到了答案。我误读了错误。编译器使用了正确版本的 basic_functor::operator() 好吧——问题是 iterator_functional::peek_next() 的返回类型。

我认为 const typename self::referenceconst S& 相同,但事实并非如此。这不是对 const 的引用,而是 const 引用!因此,const 位被忽略,因此我试图将 basic_functor::operator() 返回的 const S& 转换为 S& -- iterator_functional::peek_next() 的返回类型。

因此,解决方案不是使用const typename self::reference,而是

  inline const typename self::value_type& operator*() const
{ return m_functor(*m_it); }

相反。

谁知道!

附言在与@DavisHerring 进一步讨论后,我将改进后的工作示例放在这里。亮点:

  1. basic_functor 不需要第二个 operator()。只要是用const T模板参数创建即可。
  2. 我已删除 S 模板参数并将其从 BaseIterator 中获取。请注意,我需要将 std::remove_referenceBaseIterator::reference 一起使用,因为 const_iterator::value_type 不是常量类型。<

所以在这里(ta-da):

#include <functional>
#include <iostream>
#include <vector>
/**
* This is an empty functor which just returns back its argument.
*/
template <class T>
class basic_functor: public std::unary_function<T, T>
{
public:
typedef basic_functor self;
basic_functor()
{}

/**
* Returns back the argument passed to it.
*/
inline T& operator()(T& arg) const
{ return arg; }

};// class basic_functor

/**
* @param S type of the elements.
* @param BaseIterator type of the iterator it builds upon.
* @param functor which is applied to the element to which iterator points.
* by default it is empty functor -- the element itself is returned.
*/
template <typename BaseIterator,
typename Functor=basic_functor<
typename std::remove_reference<
typename BaseIterator::reference>::type > >
class iterator_functional:
public std::iterator<std::forward_iterator_tag,
typename Functor::result_type>
{
public:
///type defining itself
typedef iterator_functional self;
///type of the functor
typedef Functor functor_type;
///type of linear iterator
typedef BaseIterator base_iterator_type;

/**
* Constructor.
*/
iterator_functional(base_iterator_type it,
functor_type funct = functor_type()):
m_it(it),
m_functor(funct)
{
}

/**
* Copying constructor.
* @param other source of the data.
*/
iterator_functional(const self&other):
m_it(other.m_it),
m_functor(other.m_functor)
{ }

/**
* Provides access to element to which iterator points.
* @return element to which iterator points to.
*/
inline typename self::reference operator*() const
{ return m_functor(*m_it); }

/**
* Returns reference to the next element.
*/
inline const typename self::value_type& peek_next() const
{
auto temp_it = m_it;
++temp_it;
return
m_functor(*temp_it);
}//iterator_type_const

private:
base_iterator_type m_it;
functor_type m_functor;
};//iterator_functional;

typedef std::vector<int>::iterator v_int_iterator;
typedef std::vector<int>::const_iterator v_int_const_iterator;

typedef iterator_functional<v_int_iterator> iterator_type;
typedef iterator_functional<v_int_const_iterator> iterator_type_const;

int main()
{
std::vector<int> vec_1({1, 2, 3, 4});
const std::vector<int> vec_2({5, 6, 7, 8});

iterator_type it(vec_1.begin());
*it = 9;
std::cout << " *it =" << *it << "; it.peek_next() = " << it.peek_next() << std::endl;

iterator_type_const cit(vec_2.begin());
std::cout << "*cit =" << *cit << "; cit.peek_next() = " << cit.peek_next() << std::endl;
return 0;
}

关于c++ - 如何使用 C++ 中的平凡仿函数避免 "invalid initialization of reference"错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56221590/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com