注意:我更喜欢始终将我的实现与我的声明分开,即使对于仍然必须放在标头中的模板代码也是如此。因此,我倾向于使用一个用于声明的
.h
文件,并在该文件的底部包含一个用于内联和模板实现的 .hpp
文件,然后将我的非内联、非模板实现放入 .cpp
文件中。在这种情况下,可能无法遵循该偏好,或者我可能做错了什么。
我有这个初始类声明:
template<class TAddress>
class OddSource_Export InterfaceIPAddress
{
public:
InterfaceIPAddress(TAddress const &, uint16_t);
...
private:
::std::unique_ptr<TAddress> const _address;
uint16_t const _flags;
}
然后这个构造函数实现就可以工作,并且使用此类的代码可以编译:
template<class TAddress>
InterfaceIPAddress<TAddress>::
InterfaceIPAddress(TAddress const &address, uint16_t flags)
: _address(new TAddress(address)),
_flags(flags)
{
}
但我想要一个简单的基类限制。所以我首先定义这个别名:
template<class TAddress>
using Enable_If_IPAddress = ::std::enable_if_t<::std::is_base_of_v<IPAddress, TAddress>>;
更改我的类声明如下:
template<class TAddress, typename = Enable_If_IPAddress<TAddress>>
class OddSource_Export InterfaceIPAddress
...
并将我的构建实现更改如下:
template<class TAddress, typename>
但是,现在我的构造函数无法编译:
warning: missing 'typename' prior to dependent type name InterfaceIPAddress<TAddress>::InterfaceIPAddress; implicit 'typename' is a C++20 extension [-Wc++20-extensions]
InterfaceIPAddress<TAddress>::
^
typename
error: expected ')'
InterfaceIPAddress(TAddress const &address, uint16_t flags)
^
note: to match this '('
InterfaceIPAddress(TAddress const &address, uint16_t flags)
^
error: expected ';' at end of declaration
: _address(new TAddress(address)),
^
;
error: no template named '_address'; did you mean 'TAddress'?
: _address(new TAddress(address)),
^~~~~~~~
TAddress
...
我非常确定我正确定义了
enable_if_t
,因为如果我将实现移动到与声明内联,它会在没有警告或错误的情况下进行编译:
template<class TAddress, typename = Enable_If_IPAddress<TAddress>>
class OddSource_Export InterfaceIPAddress
{
public:
InterfaceIPAddress(TAddress const & address, uint16_t flags)
: _address(new TAddress(address)),
_flags(flags)
{
}
...
private:
::std::unique_ptr<TAddress> const _address;
uint16_t const _flags;
};
那么我是否错过了分离实施所需的一些额外步骤?或者使用
enable_if_t
时是否无法分离此实现?
编辑1
出于复制目的:
... above code ...
class IPAddress {};
class IPv4Address : public IPAddress {};
class IPv6Address : public IPAddress {};
int main()
{
InterfaceIPAddress<IPv4Address> address;
return 0;
}
此外,我尝试在编译器建议的位置添加
typename
,但所做的只是满足警告。没有解决编译错误。
由于您为类添加了额外的模板参数,因此需要将其传递到实现声明中,如下所示
template<class TAddress, typename Enable>
InterfaceIPAddress<TAddress, Enable>::
InterfaceIPAddress(TAddress const &address, uint16_t flags)
: _address(new TAddress(address)),
_flags(flags)
{
}