模板 class 作为参数模板:MSVC 错误 - 错误 C2977:模板参数过多 (C++98)
Template class as parameter template: MSVC error - error C2977: too many template arguments(C++98)
我需要在 MSVC(C++98) 中构建我的代码。我用模板 class 参数声明了一个模板 class。结果我在 MSVC 编译期间遇到错误:
错误 C2977:'Set':模板参数过多
Gcc 可以很好地构建此代码。
你可以自己试试:
https://godbolt.org/z/YJXLX7
给你这个代码:
#include <iostream>
#include <vector>
class Iterator
{
public:
virtual int size() = 0;
};
template <template<typename> class TContainer, class TType>
class IteratorCollectionTest
: public Iterator
{
public:
virtual int size() { m_collection.size(); }
private:
TContainer<TType> m_collection;
};
template<typename TItem>
class Set
{
public:
Set();
Iterator* createIterator();
int size();
protected:
class SetInstance;
private:
SetInstance* m_instance;
};
template<typename TItem>
class Set<TItem>::SetInstance
{
public:
Iterator* createIterator() { return new IteratorCollectionTest<Set, TItem>(); }
int size() { return m_vec.size(); }
public:
std::vector<TItem> m_vec;
};
template<typename TItem>
Set<TItem>::Set()
: m_instance(new SetInstance())
{
}
template<typename TItem>
Iterator* Set<TItem>::createIterator()
{
return m_instance->createIterator();
}
template<typename TItem>
int Set<TItem>::size()
{
return m_instance->size();
}
int main()
{
Set<int> m_serr;
Iterator* iter = m_serr.createIterator();
}
我做错了什么?
有人可以帮助我吗?
Class 模板有一个特殊的成员,叫做injected class name。在 class 模板范围内,模板名称代表 当前专业化 。它不代表模板。
new IteratorCollectionTest<Set, TItem>()
出现在 class 模板 Set
的范围内。所以 MSVC 假定 Set
参数不引用模板。它假定名称指的是 specialization,即 Set<TItem>
的类型。因此在需要模板名称的地方传递了一个 class 名称。
这是 C++98 强制要求的行为。并且此行为已在 C++11 中进行了修改,其中作为模板参数出现的模板名称不引用注入的 class 名称。在 C++11 及更高版本中,GCC 将接受代码。但是当强制使用 C++98 模式时,it complains too.
解决方法是限定名称。
Iterator* createIterator() { return new IteratorCollectionTest<::Set, TItem>(); }
由于 ::Set
是完全限定名称,它只能引用命名空间范围内的模板。
我需要在 MSVC(C++98) 中构建我的代码。我用模板 class 参数声明了一个模板 class。结果我在 MSVC 编译期间遇到错误: 错误 C2977:'Set':模板参数过多
Gcc 可以很好地构建此代码。
你可以自己试试: https://godbolt.org/z/YJXLX7
给你这个代码:
#include <iostream>
#include <vector>
class Iterator
{
public:
virtual int size() = 0;
};
template <template<typename> class TContainer, class TType>
class IteratorCollectionTest
: public Iterator
{
public:
virtual int size() { m_collection.size(); }
private:
TContainer<TType> m_collection;
};
template<typename TItem>
class Set
{
public:
Set();
Iterator* createIterator();
int size();
protected:
class SetInstance;
private:
SetInstance* m_instance;
};
template<typename TItem>
class Set<TItem>::SetInstance
{
public:
Iterator* createIterator() { return new IteratorCollectionTest<Set, TItem>(); }
int size() { return m_vec.size(); }
public:
std::vector<TItem> m_vec;
};
template<typename TItem>
Set<TItem>::Set()
: m_instance(new SetInstance())
{
}
template<typename TItem>
Iterator* Set<TItem>::createIterator()
{
return m_instance->createIterator();
}
template<typename TItem>
int Set<TItem>::size()
{
return m_instance->size();
}
int main()
{
Set<int> m_serr;
Iterator* iter = m_serr.createIterator();
}
我做错了什么? 有人可以帮助我吗?
Class 模板有一个特殊的成员,叫做injected class name。在 class 模板范围内,模板名称代表 当前专业化 。它不代表模板。
new IteratorCollectionTest<Set, TItem>()
出现在 class 模板 Set
的范围内。所以 MSVC 假定 Set
参数不引用模板。它假定名称指的是 specialization,即 Set<TItem>
的类型。因此在需要模板名称的地方传递了一个 class 名称。
这是 C++98 强制要求的行为。并且此行为已在 C++11 中进行了修改,其中作为模板参数出现的模板名称不引用注入的 class 名称。在 C++11 及更高版本中,GCC 将接受代码。但是当强制使用 C++98 模式时,it complains too.
解决方法是限定名称。
Iterator* createIterator() { return new IteratorCollectionTest<::Set, TItem>(); }
由于 ::Set
是完全限定名称,它只能引用命名空间范围内的模板。