给定一个如下所示的模板类:
template<typename Type, typename IDType=typename Type::IDType>
class Mappings
{
public:
...
Type valueFor(const IDType& id) { // return value }
...
};
如何在头文件中转发声明此类?
这就是你要做的:
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 }
...
};
请注意,默认值位于前向声明中,而不是实际定义中。
您可以声明一个模板类,其定义规定了默认参数,但任何时候引用该类时,都必须包含其所有参数,直到引入定义为止。
例如。让我们使用 struct
Foo
而不包含它:
template <class>
struct Foo;
// Note that we *must* use the template here,
// even though in the definition it'll have a default.
template <class T>
auto Func (Foo<T> foo)
{
// do stuff with Foo before it's defined:
return foo.Bar();
}
int Func (int n)
{
return n;
}
然后我们可以编译它不包含定义,例如:
int main ()
{
return Func(3);
}
...或者我们可以在after包括定义之后使用它,例如:
template <class T = bool>
struct Foo
{
T Bar () {return 9;}
};
// Now the compiler understands how to handle
// Foo with no template arguments
// (making use of its default argument)
int main ()
{
return Func(Foo<>());
}
我还没有检查标准,但这适用于 clang
/
gcc
和
-std=c++98
至
-std=c++17
,所以如果它不是正式标准,那么它看起来就是非官方标准。
namespace std
,并且出现在我检查过的示例中(使用许多编译器),但标准声明它是未定义的行为:根据 C++11 标准,17.6.4.2.1 :
如果 C++ 程序添加声明或 命名空间 std 或命名空间 std 内的命名空间的定义 除非另有说明。(我从
SO 答案 获得此信息)。
感谢Antonio在评论中指出这一点(并提供链接)。
当所有参数已知(或作为默认值提供)时减轻了对模板类前向声明的需求,以便您可以前向声明这个新类型,不再是模板了:
template<typename Type=MyDefault, typename IDType=typename Type::IDType>
class MappingsGeneric
{
...
};
class Mappings : public MappingsGeneric<> {};
然后你就可以class Mappings;
。我知道这个解决方案并不适用于所有地方,但它在我的用例中适用,因为我只在单元测试上下文中使用模板对非虚拟方法进行高性能依赖项注入。