给出如下的模板类:
template<typename Type, typename IDType=typename Type::IDType>
class Mappings
{
public:
...
Type valueFor(const IDType& id) { // return value }
...
};
有人如何在头文件中声明此类?
答案 0 :(得分:80)
这就是你要做的:
template<typename Type, typename IDType=typename Type::IDType>
class Mappings;
template<typename Type, typename IDType>
class Mappings
{
public:
...
Type valueFor(const IDType& id) { // return value }
...
};
请注意,默认值位于前向声明中,而不是实际定义中。
答案 1 :(得分:7)
您只能为模板的第一个声明声明模板的默认参数。如果您希望允许用户转发声明类模板,则应提供转发标头。如果你想使用默认值转发声明别人的类模板,那你就不走运了!
答案 2 :(得分:1)
我的回答是对其他答案的补充,因为我发现的解决方案实际上减轻了对模板类前向声明的需求,通过在所有参数都已知时创建一个新类型(或默认提供),以便这个新的类型,您可以转发声明,不再是模板:
template<typename Type=MyDefault, typename IDType=typename Type::IDType>
class MappingsGeneric
{
...
};
class Mappings : public MappingsGeneric<> {};
然后您可以class Mappings;
。我知道这个解决方案并不适用于任何地方,但它适用于我的用例,因为我只在单元测试上下文中使用了非虚拟方法的高性能依赖注入模板。
答案 3 :(得分:0)
此外,如果要声明属于某个命名空间的任何内容,则必须在该命名空间的内声明它。
例如。声明std::array
:
无法编译:
template<class _Tp, long unsigned int _Nm>
struct std::array;
但这会起作用:
namespace std
{
template<class _Tp, long unsigned int _Nm>
struct array;
}
此外,即使模板定义的类定义了默认参数,您也可以声明模板化类,但是,每次引用该类时,都必须包括其所有参数,直到引入定义为止。
例如让我们不使用它而使用std::vector
(std::vector
的第二个参数是默认定义的):
namespace std
{
template<class T, class Alloc>
class vector;
}
#include <iostream>
template <class S, class T>
void Foo (const std::vector<S,T> & vector)
{
std::cout << "do vector stuff, eg., display size = "
<< vector.size() << std::endl;
}
template <class T>
void Foo (const T & t)
{
std::cout << "do non-vector stuff..." << std::endl;
}
然后我们可以使用它而无需包含向量,例如:
int main()
{
int k = 3;
Foo(k);
return 0;
}
我们可以在 std::vector
中使用它,例如:
#include <vector>
// Now the compiler understands how to handle
// std::vector with one argument
// (making use of its default argument)
int main()
{
std::vector<int> k(3);
Foo(k);
return 0;
}