无法使用具有多个模板定义的重载功能?

时间:2018-10-10 22:53:38

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

我尝试过:

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<P>*)的函数体取决于P是否算术,该怎么办?

2 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:3)

使用标签分发方式,如下所示:

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>{});
}