我已经实现了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,无需进行转换),而非模板将必须进行提升(必须将10从int提升为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.无论采用哪种方式,都必须确保模板根本不可行.