什么时候删除模板实例比删除非模板重载更可取?
Posted
技术标签:
【中文标题】什么时候删除模板实例比删除非模板重载更可取?【英文标题】:When is deleting a template instantiation preferable to deleting a non-template overload? 【发布时间】:2014-01-28 11:19:02 【问题描述】:假设我有一个使用原始指针的模板:
template<typename T>
void processPointer(T* ptr);
我不希望使用void*
指针调用它。看来我有两个选择。我可以删除非模板重载:
void processPointer(void*) = delete;
或者我可以删除一个模板实例化:
template<>
void processPointer<void>(void*) = delete;
声明非模板重载更容易(不用尖括号)。有什么理由让我更喜欢删除模板实例化吗?
【问题讨论】:
+1,因为我自己也不知道答案。我会删除模板实例化,因为我倾向于将整个重载集视为模板。我认为稍后在阅读代码时会更容易理解发生了什么(即遵循最小意外原则)。我不知道选择一种方式是否有技术原因。 【参考方案1】:Here's one reason 支持模板版本:processPointer<void>(void*)
仍然可以直接调用,避免其他重载。
【讨论】:
+1 因为显式指定模板参数在通用代码中很常见。【参考方案2】:我看不出有什么理由在这里做模板
事实上,通过删除非模板重载,您可能会摆脱一些我现在无法想到的边缘情况模棱两可的调用,因为非模板优先于模板实例化。从而在大多数情况下使这项工作如愿以偿。
【讨论】:
【参考方案3】:这可能会提供见解:
#include <iostream>
struct X
template<typename T>
void processPointer(T* ptr)
std::cout << "Template\n";
// error: explicit specialization in non-namespace scope ‘struct X’
// template<>
// void processPointer(void*) = delete;
// Overload but no specialization
// This will prevent lookup the specialization outside the class, when no
// template argument is explicitly given. However, with an explicit
// template argument the specialization is called.
void processPointer(void*) = delete;
;
// Specialization outside the class body
template<>
void X::processPointer(void* ptr)
std::cout << "Specialization\n";
int main ()
X x;
//error: use of deleted function ‘void X::processPointer(void*)’
//x.processPointer((void*)0);
// Explicit template argument:
x.processPointer<void>((void*)0);
结论:@Casey 的答案成立。
【讨论】:
您认为这可能会带来什么见解? (我认为我知道,但是由于您实际上没有说,我不确定。请写一两句话来重申代码应该说明的内容。)template<> void X::processPointer<void>(void*) = delete;
或不带参数推导出template<> void X::processPointer(void*) = delete;
can be specialized outside the class scope。【参考方案4】:
假设您想将 void*
类型的参数 pointer
(或简单的 nullptr
)传递给您的 processPointer
函数,并且您还想调用其对 Type
类型的特化。那你应该写
processPointer(static_cast<Type>(pointer));
为
void processPointer(void*) = delete;
但是对于
template<>
void processPointer<void>(void*) = delete;
您可以编写更短的代码:
processPointer<Type>(pointer);
所以这两种变体都可以在不同的情况下使用。
但是,在某些情况下,具有非模板重载的变体的类似物可能是唯一的方法。 假设有一个带有两个参数的函数模板:
template<typename T, typename U>
void processPointer(T* ptr1, U* ptr2);
您不希望使用void*
指针作为第一个参数来调用它。 C++ 中不允许函数模板的部分特化,所以这段代码不正确:
template<typename U>
void processPointer<void, U>(void*, U*) = delete;
而且你必须使用另一个:
template<typename U>
void processPointer(void*, U*) = delete;
【讨论】:
以上是关于什么时候删除模板实例比删除非模板重载更可取?的主要内容,如果未能解决你的问题,请参考以下文章
C++ Primer 5th笔记(chap 16 模板和泛型编程)重载与模板
放大:如何删除 Auth 并使用 Api 资源添加新的 Auth 资源。错误模板错误:Fn::GetAtt 实例引用未定义资源