使用无效方法实例化类模板

时间:2014-08-20 05:03:11

标签: c++ templates c++11

我正在编写一个包含容器类的类IteratorIterable(一个具有begin()end()方法的类返回一些迭代器),以便可以迭代包装类的迭代器。这个想法基于this post。我的代码看起来像这样(为简洁起见,遗漏了一些方法):

template <class T>
class IteratorIterable
{
private:
    T& container;

public:
    typedef decltype(container.begin()) BackendIterator;

public:
    class IteratorIterator
    {
    public:
        IteratorIterator() : it() {}
        IteratorIterator(BackendIterator it) : it(it) {}
        IteratorIterator(const IteratorIterator& other) : it(other.it) {}

        IteratorIterator& operator=(const IteratorIterator& other) { if (&other == this) return *this; it = other.it; return *this; }

        BackendIterator operator*() const { return it; }
        const BackendIterator* operator->() const { return &it; }

        bool operator==(const IteratorIterator& other) { return it == other.it; }
        bool operator !=(const IteratorIterator& other) { return it != other.it; }

        IteratorIterator operator+(size_t n) { return IteratorIterator(it + n); }

        IteratorIterator& operator++() { ++it; return *this; }
        IteratorIterator operator++(int) { IteratorIterator cpy(*this); ++(*this); return cpy; }

    private:
        BackendIterator it;
    };

public:
    IteratorIterable(T& container) : container(container) {}

    IteratorIterator begin() const { return IteratorIterator(container.begin()); }
    IteratorIterator end() const { return IteratorIterator(container.end()); }
};


template <class T>
IteratorIterable<T> ItIt(T& container)
{
    return IteratorIterable<T>(container);
}

问题在于,operator+()中的IteratorIterator方法仅对随机访问BackendIterator有效,因为否则后端未定义加法运算符。我希望我的IteratorIterator仅在后端支持时提供此方法。

考虑这个示例代码:

typedef list<int> Cont;

Cont vec = {1, 2, 3, 4, 5, 6, 7, 8, 9};

IteratorIterable<Cont> itb(vec);

IteratorIterable<Cont>::IteratorIterator beg = itb.begin();
IteratorIterable<Cont>::IteratorIterator it = beg;

it++;
//it = beg+1;

printf("%d\n", **it);

这在使用it++行时编译得很好,但是 - 正如预期的那样 - 在it = beg+1行失败,因为list<int>::iterator不是随机访问。我想这是因为如果我实际上实例化 IteratorIterator::operator+(),编译器就不在乎了。

我知道模板只允许对某些模板参数有效,但这里的是模板化的,而不是方法。当该方法从未用于此特定实例化时,实例化其中一个方法无效的类模板是否正确? GCC和Clang不抱怨,但按照C ++标准是否正确?

2 个答案:

答案 0 :(得分:4)

是的,该标准保证类模板的隐式实例化仅导致声明的隐式实例化,而不是成员函数的定义。

§14.7.1[temp.inst]

  

1 ... 类模板特化的隐式实例化导致隐式   声明的实例化,但不是定义,默认参数或类成员函数的异常规范,成员类,作用域成员枚举,静态数据成员和成员模板;它会导致隐式实例化未作用域成员枚举和成员匿名联合的定义。

     

11 实现不得隐式实例化功能模板,变量模板,成员模板,非虚拟成员函数,成员类,或不需要实例化的类模板的静态数据成员...

请注意,如果您显式实例化

,您的代码将无法编译是否使用operator+
template class IteratorIterable<std::list<int>>;

除非enable_if是随机访问迭代器,否则可以通过BackendIterator向SFINAE使用过载集中的成员函数来防止这种情况发生。

template<typename Iter = BackendIterator>
typename std::enable_if<
    std::is_same<typename std::iterator_traits<Iter>::iterator_category,
                 std::random_access_iterator_tag>::value,
    IteratorIterator>::type
operator+(size_t n) 
{
    return IteratorIterator(it + n); 
}

Live demo

答案 1 :(得分:1)