这是我的(剥离)类和一个对象的实例化:
template <typename T, typename Allocator = std::allocator<T> >
class Carray {
typedef typename Allocator::size_type size_type;
// ...
explicit Carray(size_type n, const T& value, const Allocator& alloc = Allocator()) {
// ...
}
template<typename InputIterator>
Carray(InputIterator first, InputIterator last, const Allocator& alloc = Allocator()) {
// ...
}
// ...
}
Carray<int> array(5, 10);
我希望这可以调用Carray(size_type, const T&, const Allocator&)
构造函数,但事实并非如此。显然这是对template<typename InputIterator> Carray(InputIterator, InputIterator, const Allocator&)
的坚决。
我应该如何更改以使其按预期工作?我觉得它也很奇怪,因为对std::vector<int> v(5, 10)
的调用非常好。如果我在GCC的实现中查看构造函数的定义,我会发现这一点(我重命名了一些编译器实现名称,如__n
):
template<typename T, typename A = std::allocator<T> >
class vector {
typedef size_t size_type;
typedef T value_type;
typedef A allocator_type;
// ...
explicit vector(size_type n, const value_type& value = value_type(), const allocator_type& a = allocator_type());
template<typename InputIterator>
vector(InputIterator first, InputIterator last, const allocator_type& a = allocator_type());
// ...
};
似乎是一样的。
答案 0 :(得分:7)
显式构造函数需要size_t和int。您提供了两个整数。
将int
替换为InputIterator
会使模板更匹配。
如果仔细观察标准容器,您会发现它们使用一些模板元编程来确定InputIterator
是否可以是真正的迭代器,或者它是否是整数类型。然后重定向到不同的结构。
修改强>
这是一种方法:
template<class _InputIterator>
vector(_InputIterator _First, _InputIterator _Last,
const allocator_type& _Allocator = allocator_type() )
: _MyAllocator(_Allocator), _MyBuffer(nullptr), _MySize(0), _MyCapacity(0)
{ _Construct(_First, _Last, typename std::is_integral<_InputIterator>::type()); }
private:
template<class _IntegralT>
void _Construct(_IntegralT _Count, _IntegralT _Value, std::true_type /* is_integral */)
{ _ConstructByCount(static_cast<size_type>(_Count), _Value); }
template<class _IteratorT>
void _Construct(_IteratorT _First, _IteratorT _Last, std::false_type /* !is_integral */)
{ _Construct(_First, _Last, typename std::iterator_traits<_IteratorT>::iterator_category()); }
如果编译器没有std :: type_traits,你也可以使用boost :: type_traits。
答案 1 :(得分:3)
试试这个。如果传递两个int,它将消除迭代器构造函数:
template<typename InputIterator>
Carray(InputIterator first, InputIterator last,
const Allocator& alloc = Allocator(),
typename boost::disable_if<boost::is_integral<InputIterator> >::type* dummy = 0) {
}
参考:http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html
<小时/> 编辑:回应“有没有办法只使用C ++ 03 STL且没有提升?”
我不知道std :: type_traits是否在C ++ 03中 - 我总是有可用的提升,所以我只是使用它。但你可以试试这个。它适用于这种特定情况,但可能没有您需要的一般性:
template <class T> class NotInt { typedef void* type; };
template <> class NotInt<int> { };
template <typename T, typename Allocator = std::allocator<T> >
class Carray {
...
template<typename InputIterator>
Carray(InputIterator first, InputIterator last,
const Allocator& alloc = Allocator(),
typename NotInt<InputIterator>::type t = 0) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
答案 2 :(得分:2)
这应该适用于所有迭代器类型(包括指针)和当前标准。
#include <iostream>
#include <iterator>
#include <vector>
// uses sfinae to determine if the passed in type is indeed an iterator
template <typename T>
struct is_iterator_impl
{
typedef char yes[1];
typedef char no[2];
template <typename C>
static yes& _test(typename C::iterator_category*);
template <typename>
static no& _test(...);
static const bool value = sizeof(_test<T>(0)) == sizeof(yes);
};
template <typename T, bool check = is_iterator_impl<T>::value>
struct is_iterator
{
typedef void type;
};
template <typename T>
struct is_iterator<T, false>
{
};
template <typename T>
struct is_iterator<T*, false>
{
typedef void type;
};
template <typename T>
struct foo
{
explicit foo(std::size_t n, const T& value)
{
std::cout << "foo:size_t" << std::endl;
}
template<typename InputIterator>
foo(InputIterator first, InputIterator last, typename is_iterator<InputIterator>::type* dummy = 0)
{
std::cout << "foo::iterator" << std::endl;
}
};
int main(void)
{
// should not cause a problem
foo<int> f(1, 2);
// using iterators is okay
typedef std::vector<int> vec;
vec v;
foo<int> b(v.begin(), v.end());
// using raw pointers - is okay
char bar[] = {'a', 'b', 'c'};
foo<char> c(bar, bar + sizeof(bar));
}
解释,迭代器通常必须定义几个类型,例如iterator_category
,你可以利用这个和sfinae来检测真正的迭代器。复杂的是指针也是迭代器,但是没有定义这些类型(std::iterator_traits
提供了一个特殊化的东西),所以上面采用了类似的方法,如果传入的类型是一个指针,那么它是由默认视为迭代器。这种方法可以节省您测试整数类型的方法。
答案 3 :(得分:0)
第一个构造函数期望'value'参数通过引用传递,而第二个构造函数期望前两个值按值传递。根据我的经验,C ++对这种区别非常严格,尝试将整数变量而不是整数值作为对象构造函数的第二个参数传递。