【问题标题】:Overloading function with multiple template definitions not possible?无法使用多个模板定义重载函数?
【发布时间】:2018-10-10 22:53:38
【问题描述】:

我试过了:

template<typename P, typename = std::enable_if_t<std::is_arithmetic<P>::value>>
void f(std::vector<P>* a) {
    // body for arithmetic P
}

template<typename P, typename = std::enable_if_t<std::is_class<P>::value>>
void f(std::vector<P>* a) {
    // body for class P
}

本以为条件互斥会重载f,结果发现编译不通过:“函数模板已定义”。

如果我想让f(std::vector&lt;P&gt;*) 的函数体依赖于P 是否算术,该怎么办?

【问题讨论】:

标签: c++ templates c++14 overloading


【解决方案1】:

cppreference.com 上的 std::enable_if 文档说:

一个常见的错误是声明两个仅在默认模板参数上有所不同的函数模板。这是非法的,因为默认模板参数不是函数模板签名的一部分,并且用相同的签名声明两个不同的函数模板是非法的。

同一页面上的示例显示了与您的情况类似的情况,并通过更改其中一个重载的模板来解决它,同时为函数本身保持相同的签名:

// #4, enabled via a template parameter
template<class T,
         typename std::enable_if<
             !std::is_trivially_destructible<T>{} &&
             (std::is_class<T>{} || std::is_union<T>{}),
            int>::type = 0>
void destroy(T* t)
{
    std::cout << "destroying non-trivially destructible T\n";
    t->~T();
}

// #5, enabled via a template parameter
template<class T,
    typename = std::enable_if_t<std::is_array<T>::value> >
void destroy(T* t) // note, function signature is unmodified
{
    for(std::size_t i = 0; i < std::extent<T>::value; ++i) {
        destroy((*t)[i]);
    }
}
/*
template<class T,
    typename = std::enable_if_t<std::is_void<T>::value> >
void destroy(T* t){} // error: has the same signature with #5
*/

因此,您可以在代码中执行类似的操作:

template<typename P, std::enable_if_t<std::is_arithmetic<P>::value, int> = 0>
void f(std::vector<P>* a)
{
    // body for arithmetic P
}

template<typename P, typename = std::enable_if_t<std::is_class<P>::value>>
void f(std::vector<P>* a)
{
    // body for class P
}

Live Demo

【讨论】:

    【解决方案2】:

    使用标签调度,像这样或类似的:

    void f_helper(std::vector<P>* a, std::true_type) {
        /* implementation for arithmetic type P */
    }
    
    void f_helper(std::vector<P>* a, std::false_type) {
        /* implementation for class type P */
    }
    
    void f(std::vector<P>* a) {
        return f_helper(a, std::is_arithmetic<P>{});
    }
    

    【讨论】:

    • 我会选择更明确的标签名称,这样以后如果需要可以添加额外的条件:struct IsArithmeticTag {}; struct IsClassTag {}; void f_helper(..., IsArithmeticTag) { ... } void f_helper(..., IsClassTag) { ... } void f(...) { f_helper(..., typename std::conditional&lt;std::is_arithmetic&lt;P&gt;::value, IsArithmeticTag, IsClassTag&gt;::type{}); }Live Demo
    猜你喜欢
    • 1970-01-01
    • 2017-07-14
    • 2010-09-19
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 2019-10-11
    • 2020-06-01
    相关资源
    最近更新 更多