首页 > 解决方案 > 如何选择通用模板和函数重载?

问题描述

我最初试图为std::vector. 我有一个模板化的构造函数,它转发一个参数包来模仿不同的构造函数std::vectorstd::vector然后,如果 a被传入,我决定有一些专门/重载的。

在编写它时,我决定尝试不同的函数重载和模板专业化如何工作。

这是我拥有的代码:

template<typename Type>
struct myVec
{
    template <typename ...Params>
    myVec(Params&&... params)
    :vec(std::forward<Params>(params)...)
    {
        std::cout << "Generic used\n";
    }
    
    template <>
    myVec<std::vector<Type>&&>(std::vector<Type>&& params)
    {
        std::cout << "Specialization used\n";
    }
    
    myVec(std::vector<Type>& params)
    {
        std::cout << "Overload used\n";
    }
    
private:
    std::vector<Type> vec;
};

int main()
{
    std::vector<int> v{1,2,3,4,5};
    myVec<int> vec1(v);                                 // Print "Overload Used"
    myVec<int> vec2(std::vector<int> {1,2,3,4,5});      // Print "Specialization used"
    // myVec<int> vec3(&v);                             // Error, attempting to use generic template, 
                                                        // which attempt to search for std::vector(std::vector& vec), which does not exist
}

所以我的问题是他们究竟如何决定使用哪些构造函数?我以为vec1会使用通用模板,并vec3会使用重载,但显然情况并非如此。

似乎对于我的专业来说,我可以将显式模板替换<std::vector<Type>&&><std::vector<Type>>to <>,或者将其全部删除,它们对我来说都一样吗?

标签: c++c++17

解决方案


首先,您的代码无法在 GCC 上编译(我猜您正在使用 VS?)这是因为如果不专门化整个类,就无法专门化 myVec 构造函数的模板。请参阅: 非命名空间范围内的显式专业化

正如您在问题的最后一段中所说,无论如何都不需要专业化,因此您可以将其删除。此代码有效:

#include <iostream>
#include <vector>

template<typename Type>
struct myVec
{
    template <typename ...Params>
    myVec(Params&&... params)
    :vec(std::forward<Params>(params)...)
    {
        std::cout << "Generic used\n";
    }
    
    myVec(std::vector<Type>&& params)
    {
        std::cout << "Specialization used\n";
    }
    
    myVec(std::vector<Type>& params)
    {
        std::cout << "Overload used\n";
    }
    
private:
    std::vector<Type> vec;
};

int main()
{
    std::vector<int> v{1,2,3,4,5};
    myVec<int> vec1(v);                              // Print "Overload Used"
    myVec<int> vec2(std::vector<int> {1,2,3,4,5});    // Print "Specialization used"
    // myVec<int> vec3(&v);                          // Error, attempting to use generic template, 
                                                        // which attempt to search for std::vector(std::vector& vec), which does not exist
}

vec1 使用重载模板,因为,嗯....它是直接匹配的。没有其他构造函数与参数匹配v。这是因为当您将 v 传递给构造函数时,它将作为左值引用传递,即std::vector<int>&(或const vector<int>&)。请参阅左值参考:

https://en.cppreference.com/w/cpp/language/reference

vec2 使用 'specialized' 模板,因为它需要一个右值引用并将std::vector<int>{1, 2, 3, 4, 5}作为右值引用传递。所以这是一个精确的匹配。


推荐阅读