使用模板专门化,我编写了一系列函数,它们都具有相同的名称和相同的参数类型,但返回由模板参数指定的类型的数据:
template<typename T> T f (int x); // Purposefully unimplemented.
template<> inline uint8_t f<uint8_t> (int x) { return f8 [x]; }
template<> inline uint16_t f<uint16_t>(int x) { return f16 [x]; }
template<> inline uint32_t f<uint32_t>(int x) { return f32 [x]; }
template<> inline uint64_t f<uint64_t>(int x) { return f64 [x]; }
然后我可以写这样的代码:
uint32_t a = f<uint32_t>(3);
uint64_t b = f<uint64_t>(7);
我特意让默认模板保持未实现状态,以便在有人试图将某个版本的f用于除我定义的专用类型之外的任何类型时,产生链接器错误。
我有两个问题:
1)如果有人试图使用比我现在得到的更友好的默认模板,是否有某种方法可以使用static_assert()
(或其他)产生编译错误(而不是链接器错误):* 未定义对'int f(int)'的引用 *?
2)有没有什么方法可以让模板保持与程序员相同的接口,但不需要模板专门化?(也就是说,有没有什么方法可以完全避免默认模板?)
2条答案
按热度按时间n53p2ov01#
不要搞特殊化超驰。
这使用标记调度来选择覆盖,而不是使用专门化。
如果没有找到显式专用化,则会选择
=delete
模板,并立即得到编译器错误。有趣的是,如果你想用新的类型来扩展它,比如
namespace lib{ struct bigint; }
,你可以在namespace lib
中放置一个fimpl(fimpl::tag_t<bigint>, int)
重载,它会工作。如果你同意用
f(tag<uint8_t>, 7)
代替f<uint8_t>(7)
,你也可以不用f
作为模板。只要去掉fimpl
命名空间(把东西移走),把fimpl::fimpl
重命名为f
,去掉=delete
ed模板函数,加上template<class T> constexpr tag_t<T> tag{};
。但是在调用点语法有点不同。c90pui9n2#
1.如果有人试图使用比我现在得到的模板更友好的默认模板,我是否可以使用static_assert(或其他方法)来产生编译错误(而不是链接器错误):未定义对'int f(int)'的引用?
我认为更好的解决方案是路人在评论中建议的:
但是如果您真的想使用
static_assert()
......我想您可以尝试以下方法1.有没有什么方法可以让模板保持与程序员相同的接口,但不需要模板专门化?(也就是说,有没有什么方法可以完全避免默认模板?)
我不清楚你到底想要什么。
你不想专门化,你想避免默认模板?
假设您只需要只适用于特定类型集的默认模板,我想您可以使用SFINAE。
举个例子,只有当
T
是整数类型时,才启用下面的f()
。下面是一个完整的编译示例