如何转发声明C++模板类?

问题描述 投票:0回答:4

给定一个如下所示的模板类:

template<typename Type, typename IDType=typename Type::IDType>
class Mappings
{
public:
    ...
    Type valueFor(const IDType& id) { // return value }
    ...
};

如何在头文件中转发声明此类?

c++ templates forward-declaration
4个回答
149
投票

这就是你要做的:

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 }
    ...
};

请注意,默认值位于前向声明中,而不是实际定义中。


19
投票

可以声明一个模板类,其定义规定了默认参数,但任何时候引用该类时,都必须包含其所有参数,直到引入定义为止。

例如。让我们使用 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在评论中指出这一点(并提供链接)。


8
投票
您只能为模板的第一次声明声明模板的默认参数。如果您希望允许用户转发声明类模板,您应该提供转发标头。如果您想使用默认值转发声明其他人的类模板,那么您就不走运了!


2
投票
我的答案补充了其他答案,因为我发现的解决方案实际上通过创建一个新类型

当所有参数已知(或作为默认值提供)时减轻了对模板类前向声明的需求,以便您可以前向声明这个新类型,不再是模板了:

template<typename Type=MyDefault, typename IDType=typename Type::IDType> class MappingsGeneric { ... }; class Mappings : public MappingsGeneric<> {};
然后你就可以

class Mappings;

。我知道这个解决方案并不适用于所有地方,但它在我的用例中适用,因为我只在单元测试上下文中使用模板对非虚拟方法进行高性能依赖项注入。

© www.soinside.com 2019 - 2024. All rights reserved.