假设有以下模板类:
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
{
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 }
...
};
请注意,默认情况下在前向声明中而不是实际定义中。
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);
}
...或者在包含定义后使用它,例如:
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<>());
}
我没有检查过标准,但这适用于使用-std=c++98
到-std=c++17
的clang
/gcc
,因此如果它不是正式的标准,则看起来是非正式的。
尽管理论上这应该适用于namespace std
,并且在我检查的示例中(使用许多编译器)似乎也是如此,但标准规定它是未定义行为:根据C++11标准,17.6.4.2.1:
除非另有规定,否则C++程序的行为将是未定义的,如果它添加了声明或定义到
namespace std
或namespace std
内的命名空间。
(我从一个SO答案中获得了这个信息。)
感谢Antonio在评论中指出这一点(并提供链接)。
你只能为模板的第一个声明指定默认参数。如果你想允许用户前向声明一个类模板,你需要提供一个转发头文件。如果你想使用默认值前向声明别人的类模板,那就没戏了!
我的回答补充了其他回答,因为我发现的解决方案实际上通过创建一个新类型在所有参数已知时(或提供默认值)来减少了模板类前向声明的需求,因此这个新类型不再是一个模板,可以进行前向声明:
template<typename Type=MyDefault, typename IDType=typename Type::IDType>
class MappingsGeneric
{
...
};
class Mappings : public MappingsGeneric<> {};
class Mappings;
。我知道这种解决方案并不适用于所有情况,但在我的用例中,我仅在单元测试上下文中使用模板进行高性能依赖注入,用于非虚拟方法。
Foo<> foo;
。 - Oleksastd::vector
。 - Antonio