具有编译时间常数的模板特化
Posted
技术标签:
【中文标题】具有编译时间常数的模板特化【英文标题】:Template specialization with compile time constant 【发布时间】:2014-08-18 11:55:14 【问题描述】:我正在尝试为具有编译时间常数的模板类构建特化。
模板类如下所示:
template<class TNativeItem, class TComItem = void,
VARTYPE _vartype = _ATL_AutomationType<TComItem>::type>
class InOutComArray
private:
CComSafeArray<TComItem, _vartype> _safeArray;
// ...
public:
InOutComArray(
TNativeItem* items, size_t length,
std::function<TComItem(const TNativeItem&)> convertToCom,
std::function<TNativeItem(const TComItem&)> convertFromCom)
: _safeArray(length)
// ...
// ...
;
用法例如:
InOutComArray<BOOL, VARIANT_BOOL, VT_BOOL>(
items, length, BOOLToVARIANT_BOOL, VARIANT_BOOLToBOOL));
但是,也存在不需要转换的类型,我想为此提供一个简写版本:
InOutComArray<LONG>(items, length);
我尝试这样实现它:
template<class TItem, VARTYPE _vartype = _ATL_AutomationType<TItem>::type>
class InOutComArray<TItem, void, _vartype>
: public InOutComArray<TItem, TItem, _vartype>
public:
InOutComArray(TItem* items, size_t length)
: InOutComArray<TItem, TItem, _vartype>(
items, length, NoConverter<TItem>, NoConverter<TItem>)
;
但是,我收到以下错误:
'_vartype' : 部分特化不允许使用默认模板参数
有什么办法吗?
【问题讨论】:
报错信息很清楚。 @40two 你的评论没有帮助。我专门询问了一种绕过该错误消息的方法。 【参考方案1】:您首先将默认参数定义为void
和_ATL_AutomationType<TComItem>::type
,因此当只给出一个参数X 时,您希望InOutComArray<X>
成为InOutComArray<X, void, _ATL_AutomationType<void>::type>
。
您的部分专业化与此相矛盾:InOutComArray<X>
应为InOutComArray<X, X, _ATL_AutomationType<X>::type>
。
根据您认为第二个参数更可能是什么(即void
或与第一个参数相同),您可以首先将第二个参数默认为第一个:
template<class TNativeItem, class TComItem = TNativeItem,
VARTYPE _vartype = _ATL_AutomationType<TComItem>::type>
这样就覆盖了部分特化的行为,除了额外的构造函数。这可以通过使用构造函数的默认参数来实现:
template<class TNativeItem, class TComItem = TNativeItem,
VARTYPE _vartype = _ATL_AutomationType<TComItem>::type>
class InOutComArray
public:
InOutComArray(
TNativeItem* items, size_t length,
std::function<TComItem(const TNativeItem&)> convertToCom = NoConverter<TNativeItem>(),
std::function<TNativeItem(const TComItem&)> convertFromCom = NoConverter<TNativeItem>());
;
【讨论】:
非常感谢您提供这么好的信息!这看起来很优雅,但是,以下情况并不能解决:InOutComArray<LONG, VT_I8>(items, length)
。有没有办法允许这样做?
std::enable_if
似乎不起作用,我收到了'type' : is not a member of 'std::enable_if<false,size_t>'
。 Looks like不能这样用吗?
一个InOutComArray<LONG, VT_I8>
将是一个InOutComArray<LONG, VT_I8, _ATL_AutomationType<VT_I8>::type>
- 我想这不是你想要的? (不知道 VT_I8 可能是什么)如果您正在寻找“重载”第二个模板参数,那么您可以拥有 TComItem 或 VARTYPE(无论是什么)。我不确定这是否可能 - 您必须在其中一种情况下指定所有参数。
我的意思是我可以写InOutComArray<LONG, VT_I8>
并得到InOutComArray<LONG, LONG, VT_I8>
。
@DanielHilgarth:更正了 enable_if 部分,不需要它。至于您的最后一条评论:您可以将InOutComArray<X, Y>
解析为InOutComArray<X, Y, _ATL_AutomationType<Y>::type>
或InOutComArray<X, X, Y>
,但有时不是前者,有时不是后者。你似乎两者都想要——你必须做出决定。【参考方案2】:
根据标准§14.5.5/8 Class template partial specializations [temp.class.spec]:
特化的模板参数列表不应包含默认模板参数值。
因此,编译器理所当然地抱怨,因为在您的部分特化中,您为 VARTYPE _vartype = _ATL_AutomationType<TItem>::type
提供了默认模板参数值。
【讨论】:
感谢您提供有关评论的详细信息。但我并没有真正问编译器是否正确。【参考方案3】:有什么办法吗?
是的,从部分特化中删除默认模板参数。你不需要它。
根据主模板:
template<class TNativeItem, class TComItem = void,
VARTYPE _vartype = _ATL_AutomationType<TComItem>::type>
class InOutComArray
这些类型是等价的:
InOutComArray<LONG>
InOutComArray<LONG, void, _ATL_AutomationType<TComItem>::type>
每当InOutComArray
用TComItem = void
实例化时,您都会得到部分特化:
template<class TItem, VARTYPE _vartype>
class InOutComArray<TItem, void, _vartype>
【讨论】:
哈,确实。但是,以下情况并不能由此解决:InOutComArray<LONG, VT_I8>(items, length)
。有没有办法允许这样做?
这不是专业化就能解决的。特化不会引入另一种提供模板参数的方式。以上是关于具有编译时间常数的模板特化的主要内容,如果未能解决你的问题,请参考以下文章
C++模板详解:泛型编程模板原理非类型模板参数模板特化分离编译
C++初阶:模板进阶非类型模板参数 | 模板的特化 | 模板分离编译
C++初阶:模板进阶非类型模板参数 | 模板的特化 | 模板分离编译
C++初阶:模板进阶非类型模板参数 | 模板的特化 | 模板分离编译