2014-01-09 64 views
18

假设我有与原始指针工作的模板:什么时候删除模板实例更适合删除非模板重载?

template<typename T> 
void processPointer(T* ptr); 

我不希望这种与void*指针调用。看来我有两个选择。我可以删除一个非模板超载:

void processPointer(void*) = delete; 

或者,我可以删除模板实例:

template<> 
void processPointer<void>(void*) = delete; 

声明非模板超载容易(用尖括号没有把玩)。是否有我为什么宁愿删除模板实例化的原因?

+1

+1,因为我不知道自己的答案。我想删除模板实例,因为我倾向于将整个重载集合看作模板。我认为在阅读代码时(即遵循最少惊喜的原则),将会更容易理解后来的情况。我不知道是否有技术上的理由来选择这种或那种方式。 – utnapistim

回答

4

我看不出有任何理由去这里模板化

事实上,通过删除非模板超载可能摆动你的出路,我不能想到的右边缘的一些情况暧昧电话现在,由于非模板优先于模板实例化。从而在大多数情况下按照需要进行这项工作。

4

这可能洞察:

#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的答案成立。

+2

你认为这可能会给你什么样的见解? (我*认为*我知道,但是因为您没有真正说过,所以我不确定,请写一两句话来重申代码应该说明什么。) –

+1

'template <> void X :: processPointer无效X :: processPointer(void *)= delete;'[可以在类范围之外专门化](http://coliru.stacked- crooked.com/a/d5e781c971aa54b0“在Coliru的演示代码”)。 – Casey

16

Here's one reason赞成模板版本:processPointer<void>(void*)仍然可以直接调用,避免其他重载。

+2

作为明确指定模板参数的+1在通用代码中很常见。 –

0

假设你想类型void*(或简称nullptr)的参数pointer传递到您的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;