【问题标题】:c++ template parameter with map declaration带有地图声明的c ++模板参数
【发布时间】:2012-01-06 12:15:03
【问题描述】:

这段代码有什么问题:

标题:

#include <map>

using namespace std;

template<class T>
class ValueCollection
{
public:
    ValueCollection(void);

    int getValueCount(void);

    map<string, T> Values;
};

实施:

#include "ValueCollection.h"

ValueCollection<class T>::ValueCollection(void)
{
}

int ValueCollection<class T>::getValueCount(void)
{
    return Values.size();
}

测试:

#include "ValueCollection.h"

TEST(ValueCollection_TestCases, Default_Constructor_MapIsEmpty)
{
    ValueCollection<int>* target = new ValueCollection<int>;

    int expected = 0;
    int actual = target->getValueCount();

    ASSERT_EQ(expected, actual);
}

这是错误:

Error   1   error C2079: 'std::_Pair_base<_Ty1,_Ty2>::second' uses undefined class 'T'  c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility  167 1   Refactor01

【问题讨论】:

  • 您是否曾在任何时候加入过&lt;string&gt;
  • 很多事情都错了。简短的回答:您不能将定义与模板的声明分开。
  • 永远不要在头文件中说using namespace std;
  • 添加typename,如`map Values;`?
  • @KerrekSB:我并不是在抨击using 本身,而是在使用别名时直接注入名称的想法同样有效(至少在命名空间级别)。在 C++11 中,这是别名。

标签: c++ templates stl map


【解决方案1】:

几个问题。

您最直接的编译器错误是由类模板成员函数的实现中的不正确语法引起的。您必须在类模板成员的定义前加上 template 关键字。也就是说:

template<class T> ValueCollection<T>::ValueCollection(void)
{
}

template<class T> int ValueCollection<T>::getValueCount(void)
{
    return Values.size();
}

还有另一个问题,随着程序的增长,它只会在以后变得明显。您不能在一个Translation Unit 中定义模板函数或类并在另一个中使用它们。编译器必须在每个翻译单元中都有完整的定义。

通常,实现这一点的方法是直接在头文件中定义模板函数,就在它们被声明的地方。在你的情况下:

template<class T>
class ValueCollection
{
public:
    ValueCollection(void)
    {
    }

    int getValueCount(void)
    {
        return Values.size();
    }

    map<string, T> Values;
};

这只是实现这一目标的一种方法——还有其他方法。另一种方式是使用所谓的“inclusion method”:

ValueCollection.h

template<class T>
class ValueCollection
{
public:
    ValueCollection(void);

    int getValueCount(void);

    map<string, T> Values;
};

#include "ValueCollection.hpp:

ValueCollection.hpp

template<class T> ValueCollection<T>::ValueCollection(void)
{
}

template<class T> int ValueCollection<class T>::getValueCount(void)
{
    return Values.size();
}

另一种方法是为每个想要使用模板的翻译单元提供一个新定义,但这非常不寻常。 (其实在我 15 年的 C++ 编程中,我从来没有这样做过)

【讨论】:

  • 感谢所有提供帮助的人 - 我喜欢 StackOverflow 社区。我不仅现在可以正常工作,而且了解原因。
【解决方案2】:

实现应该是:

#include "ValueCollection.h"

template <class T>
ValueCollection<T>::ValueCollection(void)
{
}

template <class T>
int ValueCollection<T>::getValueCount(void)
{
    return Values.size();
}

【讨论】:

  • 不过,这只会开始打开潘多拉的蠕虫罐。
  • @KerrekSB:我们拭目以待。我觉得你反应过度了。没有人说他将“实施”放在单独的 TU 中。事实上,OP 并没有说 哪里 它去:)。这家伙也在工作测试驱动。那是一个 pre !
  • 嗯,她确实说了“标题”和“实现”,所以我赌的是“为什么我会得到这个链接器错误”。不过,我很欣赏你的乐观!
  • 感谢所有提供帮助的人 - 我喜欢 StackOverflow 社区。我不仅现在可以正常工作,而且了解原因。
【解决方案3】:

您也需要在实现文件中的每个方法之前添加template &lt;class T&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-20
    • 1970-01-01
    • 1970-01-01
    • 2021-05-28
    • 1970-01-01
    • 1970-01-01
    • 2019-01-24
    • 1970-01-01
    相关资源
    最近更新 更多