c++ - forward_list : assign(_InputIterator __first, _InputIterator __last)/assign(size_type __n, const _Tp& __val)

标签 c++ c++11 forward-list

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

我写了下面的片段,只是为了说明问题:

测试.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

测试.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,无需转换),而非模板将必须进行提升(必须提升10intsize_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 : assign(_InputIterator __first, _InputIterator __last)/assign(size_type __n, const _Tp& __val),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30809075/

相关文章:

c++ - 对 unicode 文件使用 getline 时出现问题

c++ - [ ] - 运算符中的加法和增量表达式

c++ - 是否有利用 move 的 back_inserter 变体?

c++ - 在线程 A 中创建 std::thread 对象,加入线程 B

c++ - 为什么没有给 std::forward_list 一个 count() 成员函数?

c++ - std::forward_list 中可以存在循环吗?

c++ - std::unordered_map 不可分配的内部对。如何?

c++ - 具有三个不同整数的排序数组,仅通过一次

c++ - 将 std::forward 与 auto&& 一起使用是正确的做法吗

c++ - list 和 forward_list 性能之间的区别?