我已经实现了forward_list的一个子集,并想测试assign(size_type __n, const _Tp& __val)方法,但是由于编译器想要调用assign(_InputIterator __first, _InputIterator __last)方法,因此出现编译器错误。

我编写了以下代码片段,以说明问题:

test.h

#ifndef TEST_H
#define TEST_H

#include <utility> // Just to get the std::size_t

template<typename _Tp>
class forward_list {
  public:
    typedef std::size_t size_type;

    void assign(size_type n, const _Tp& val)
    {
      printf("%s\n", __PRETTY_FUNCTION__);
    }

    template<typename _InputIterator>
    void assign(_InputIterator first, _InputIterator last)
    {
      printf("%s\n", __PRETTY_FUNCTION__);
    }
};

#endif // TEST_H

test.cpp
#include <stdlib.h>
#include <stdio.h>
#include "test.h"

int main()
{
  forward_list<int> l;
  l.assign(10, 5);
  return 0;
}

执行的输出为:
void forward_list<_Tp>::assign(_InputIterator, _InputIterator) [with _InputIterator = int; _Tp = int]

我想调用assign(size_type __n, const _Tp& __val)方法。

编译器版本(以防万一):g++ (Debian 4.7.2-5) 4.7.2
我已经使用了与std::forward_list中使用的签名相似的签名,并使用了以下代码片段(使用STL):
std::forward_list<int> l;
l.assign(10, 5);

编译器知道必须调用assign(size_type __n, const _Tp& __val)并且不会感到困惑。我想念什么?

最佳答案

调用l.assign(10, 5);时,有两个可行的重载:

void assign(size_type n, const int& val)

template <>
void assign(int first, int last)

当我们说非模板函数比模板函数更可取时,只有当二者具有不可区分的转换序列时,这才是正确的。但是在这种情况下,功能模板将完全匹配(您的两个参数均为int,无需进行转换),而非模板将必须进行升级(必须将10int升级为size_t)。因此,首选函数模板重载。

至于如何修复它,您只需要使模板不再可行即可。这涉及为输入迭代器编写type_trait,使用void_t并不难:
template <typename... >
using void_t = void;

template <typename T, typename = void>
struct is_input_iterator : std::false_type { };

template <typename T>
struct is_input_iterator<T, void_t<
    decltype(std::declval<T>() == std::declval<T>()),
    decltype(std::declval<T>() != std::declval<T>()),
    decltype(*std::declval<T>()),
    decltype(++std::declval<T>()),
    decltype(std::declval<T>()++)
    >> : std::true_type { };

然后要求is_input_iterator:
template <typename _InputIterator,
          typename = std::enable_if_t<is_input_iterator<_InputIterator>::value>>
void assign(_InputIterator first, _InputIterator last);

还有很多其他方式可以执行这种操作,我碰巧喜欢void_t。无论采用哪种方式,都必须确保模板根本不可行。

关于c++ - forward_list:分配(_InputIterator __first,_InputIterator __last)/分配(size_type __n,const _Tp&__val),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30809075/

10-11 23:13