5

这是我的(剥离的)类和一个对象的实例化:

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&)

我应该改变什么才能使这项工作按预期进行?我也觉得这很奇怪,因为调用 tostd::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());

    // ...
};

这似乎是一样的。

4

4 回答 4

7

显式构造函数需要一个 size_t 和一个 int。您提供了两个整数。

替换intInputIterator使模板更匹配。

如果您仔细观察标准容器,您会发现它们使用一些模板元编程来确定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。

于 2011-05-18T20:17:39.407 回答
3

尝试这个。如果传递了两个整数,它将不考虑迭代器构造函数:

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 中——我总是有可用的 boost,所以我只是使用它。但是你可以试试这个。它适用于这种特定情况,但可能没有您需要的通用性:

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";
  }
};
于 2011-05-18T20:35:07.503 回答
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提供了专门化),所以上面采用了类似的方法,如果传入的类型是指针,则默认将其视为迭代器. 这种方法使您不必测试整数类型。

见演示:http ://www.ideone.com/E9l1T

于 2011-05-18T22:22:24.757 回答
0

第一个构造函数期望“值”参数通过引用传递,而第二个构造函数期望前 2 个值通过值传递。根据我的经验,C++ 对这种区别非常严格,请尝试将整数变量而不是整数值作为第二个参数传递给对象构造函数。

于 2011-05-18T21:22:04.603 回答