【问题标题】: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,因为我自己也不知道答案。我会删除模板实例化,因为我倾向于将整个重载集视为模板。我认为稍后在阅读代码时会更容易理解发生了什么(即遵循最小意外原则)。我不知道选择一种方式是否有技术原因。

标签: c++ templates c++11 overloading


【解决方案1】:

Here's one reason 支持模板版本:processPointer&lt;void&gt;(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&lt;&gt; void X::processPointer&lt;void&gt;(void*) = delete;或不带参数推导出template&lt;&gt; 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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-19
      • 1970-01-01
      • 2012-03-13
      • 2019-02-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多