为什么这个构造函数重载不正确解析? [英] Why does this constructor overload resolve incorrectly?

查看:131
本文介绍了为什么这个构造函数重载不正确解析?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

This is my (stripped) class and instantiation of one object:

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

I would expect this to call the Carray(size_type, const T&, const Allocator&) constructor, but it doesn't. Apparantly this resolutes to template<typename InputIterator> Carray(InputIterator, InputIterator, const Allocator&).

我应该如何更改,我发现它很奇怪,因为调用 std :: vector< int> v(5,10)工作完全正常。如果我看看在我的GCC的实现中的构造函数的定义,我发现这(我重命名一些编译器实现名称,如 __ n ):

What should I change to make this work as intended? I find it weird also, because a call to std::vector<int> v(5, 10) works perfectly fine. And if I look at the definition of the constructors in my GCC's implementation I find this (I renamed some compiler-implementation names, like __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());

    // ...
};

看起来是一样的。

推荐答案

这将适用于所有迭代器类型(包括指针)和当前标准。

This should work with all iterator types (including pointers) and the current standard.

#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 提供了一个特殊化),所以上面采用了类似的方法,if传入的类型是一个指针,那么它被默认处理为一个迭代器。这种方法可以节省您不必测试积分类型。

Explanation, an iterator must normally define several types such as iterator_category, and you can take advantage of this and sfinae to detect real iterators. Complication is that pointers are also iterators, but don't have these types defined (something std::iterator_traits provides a specialization for), so the above takes a similar approach, if the passed in type is a pointer, then it is by default treated as an iterator. This approach saves you having to test for integral types.

查看演示: http://www.ideone.com / E9l1T

这篇关于为什么这个构造函数重载不正确解析?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆