【问题标题】:C++ template class overload [] operatorC++ 模板类重载 [] 运算符
【发布时间】:2012-07-21 21:02:56
【问题描述】:

关于模板参数,我想重载模板类的 [] 运算符。像这样:

template<
    typename T,
    template<typename> class Property, 
    template<typename> class Key1, 
    template<typename> class Key2>
class a_map 
{
public:
    const Property<T>& operator[](const Key1<T>& k) const
    { return _values[k.index()]; }
    const Property<T>& operator[](const Key2<T>& k) const
    { return _values[k.index()]; }
protected:
    std::vector<Property<T> > _values;
};

我会这样使用这个类:

int main()
{
    a_map<float, prop, key_a, key_b> pm;
}

基本上我希望能够访问_values 向量内的元素,而不必担心Key 类型。重要的是他们有一个index() 成员。

但是我得到以下错误

错误 C2535: 'const 属性 &a_map::operator [](const Key1 &) const' : 成员函数已定义或 声明

尽管key_akey_b 是两个完全不同的types 类模板。

我错过了什么吗?编译器是否担心在某些情况下 Key1&lt;T&gt;Key2&lt;T&gt; 可能实际上是同一类型?

编辑 这些是main中使用的类模板

template<typename T>
struct prop 
{
    T weight;
    T height;
};


template<typename T>
class key_a
{
public:
    int index() { return _i; }
private:
    int _i;
};

template<typename T>
class key_b
{
public:
    int index() { return 3; } // Always return 3

编辑 我正在使用 MVC++ 2008 编译器。

【问题讨论】:

  • 您是否 100% 确信 Key1Key2 是不同的模板?试试std::vectorstd::list 作为测试,或者类似的东西。
  • key_akey_b - 类型?根据您的声明key_akey_b 必须是类模板,而不是类型。您将第二个、第三个和第四个模板参数声明为 template-template 参数。因此,您必须指定 templates 作为参数。如果key_akey_b 只是类型,你的代码甚至不应该编译。请提供一个具体示例,说明测试中出现该错误的 key_akey_b
  • 这是编译器错误还是链接器错误?
  • @AndreyT 我的错。 key_a 和 key_b 确实是类模板。我已经更正了。
  • @Code-Guru 我相信这是编译器错误。

标签: c++ templates map operator-overloading


【解决方案1】:

既然你的两个 operator[] 除了参数类型之外都是一样的,为什么不给它们模板呢?

    template <typename TT>
    const Property<T>& operator[](const TT& k) const
    {
        return _values[k.index()];
    }

【讨论】:

  • 因为我想更好地控制键类型。我希望编译器不允许某些类型的键。 (只允许 Key1 和 Key2)
  • @CatPlusPlus:我宁愿倾向于“没有理由将其复杂化超过 2 行”,但每个人都有自己的...
【解决方案2】:

您需要将您的index() 函数声明为const,因为在a_map 模板中您通过const 对象调用它们

template<typename T> class key_a {
public:
    int index() const // <- `const` is necessary
      { return _i; }
private:
    int _i;
};

template<typename T> class key_b {
public:
    int index() const // <- `const` is necessary
      { return 3; } 
};

但除此之外,一切都可以编译并且对我来说工作正常。


在 VS2010 编译器中尝试过,得到和你一样的错误。这显然是 MSVC++ 编译器中的编译器错误。模板-模板参数的处理不正确。

为了解决这个问题,我可以使用这种技术

template<
    typename T,
    template<typename> class Property, 
    template<typename> class Key1, 
    template<typename> class Key2>
class a_map 
{
public:
    const Property<T>& operator[](const typename Key1<T>::self& k) const
    { return _values[k.index()]; }
    const Property<T>& operator[](const typename Key2<T>::self& k) const
    { return _values[k.index()]; }
protected:
    std::vector<Property<T> > _values;
};

并将关键模板定义为

template<typename T> class key_a {
public:
    typedef key_a self;
    int index() const { return _i; }
private:
    int _i;
};

template<typename T> class key_b {
public:
    typedef key_b self;
    int index() const { return 3; } 
};

这很不优雅,但它可以在 MSVC++ 编译器中正常工作。

【讨论】:

    【解决方案3】:

    像这样编译...注意应该如何定义 Prop/K1/K2。

    #include <vector>
    
    template<
        typename T,
        template<typename> class Property, 
        template<typename> class Key1, 
        template<typename> class Key2>
    class a_map 
    {
    public:
        const Property<T>& operator[](const Key1<T>& k) const
        { return _values[k.index()]; }
        const Property<T>& operator[](const Key2<T>& k) const
        { return _values[k.index()]; }
    protected:
        std::vector<Property<T> > _values;
    };
    
    template <typename T> struct K1 { int index() const { return 0; } };
    template <typename T> struct K2 { int index() const { return 0; } };
    template <typename T> struct Prop { };
    
    int main()
    {
        a_map<float, Prop, K1, K2> m;
    }
    

    【讨论】:

    • 请记住,编译器甚至不会查看未使用的模板函数。您的主要功能不使用operator[],因此不会检查这两个例程。添加此K1&lt;int&gt; k1; m[k1];,您将获得error: no match for ‘operator[]’ in ‘m[k1]
    • @Adam:当然,不匹配:在 Tony 的示例中,a_map 是用T = float 实例化的。你为什么要使用K1&lt;int&gt;
    • @Tony Delroy 我已经尝试了您的确切代码,但我的编译器 MVSC 2008 中仍然出现错误
    • @Adam:编译器确实会查看未使用的函数 - 尽管没有那么彻底 - 这就是为什么您有时需要使用 typename 以便它们可以通过检查而模板参数没有已知....我有足够的信心,错误是在这个阶段我觉得没有必要使用它们;-)。
    • @Iam:哎呀——在 Linux 上使用 GNU——你可能想试试comeaucomputing.com/tryitout——如果它在那里工作,那么它可能是你的编译器......
    猜你喜欢
    • 2016-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-14
    • 1970-01-01
    • 2013-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多