专门用于任意类型向量的模板

Specialise template for vector of arbitrary type

我有一个用于将对象转换为字符串的模板函数(这是来自库,我无法更改它):

template <typename Q> std::wstring ToString(const Q& q) { static_assert(false, "Must specialise"); }

现在,我想用参数 std::vector<Gene> 调用它,其中 Gene 是一个简单的 class,其细节并不重要。当然,要做到这一点,我需要专门化模板,所以我这样做:

template<> std::wstring ToString(const std::vector<Gene>& q){...}

假设我有另一个 class、Cell,我想将 ToString 函数专门用于 std::vector<Cell>。我将不得不进行另一个明确的专业化,与 std::vector<Gene> 版本具有相同的主体。

转换 std::vector 的逻辑不依赖于实际的内容类型(int、GeneCell、另一个 std::vector 等), 所以创建一个可以与任何 std::vector 一起工作的模板专业化是有意义的。但我想不出一个简单的方法来做到这一点。目前,我目前有一个 VectorToString 函数,并转发来自 ToString(std::vector<Gene>>)ToString(std::vector<Cell>) 的调用,但这仍然需要我为每个元素类型实现一个专门化。

因此,对于实际问题:是否可以为任意 std::vector 创建一个专业化,我该怎么做?而且,作为奖励问题,这是否可以推广到任何支持 std::beginstd::end 的任意集合?

我看过这个 this question 并尝试像这样声明专业化:

template<typename E> std::wstring ToString<std::vector<E>>(const std::vector<E>& t){...}

但这在 C2768 中失败:非法使用显式模板参数(“编译器无法确定函数定义是否应该是函数模板的显式特化,或者函数定义是否应该用于一个新函数。”),这是有道理的,因为我们有相同的函数名称和模板参数数量,以及相似的签名。

供参考,本人使用Visual C++ 2015 RC,原模板函数来源于原生测试库

您几乎做对了,但是对于您不应该特化它们的函数,您应该像这样简单地重载它们:

template <typename Q> std::wstring ToString(const Q& q) {
    return L"Original";
}
template<typename E> std::wstring ToString(const std::vector<E>& t) {
    return L"overload";
}

有关 运行 示例,请参见 http://ideone.com/G3r0Vt

之所以有效,是因为在选择要调用的重载时,const std::vector<E> 被认为是 "better" 而不是 const Q&,因此使用了重载。

在您的代码中使用这些方法时,您应该考虑 ADL

我有下一个例子给你。接下来尝试使用:

template<typename E> std::string ToString(const std::vector<E>& t)
{
    std::stringstream resStr;
    for (const E& element : t)
    {
        resStr << element << " ";
    }
    return resStr.str();
}

int _tmain(int argc, _TCHAR* argv[])
{
    std::vector<int> v1;
    v1.push_back(22);
    v1.push_back(33);
    std::vector<double> v2;
    v2.push_back(54.656);
    v2.push_back(44.656);
    auto strInt = ToString(v1);
    auto strDouble = ToString(v2);
    return 0;
}

我将以下内容用于基本类型的向量:

namespace Microsoft
{
    namespace VisualStudio
    {
        namespace CppUnitTestFramework
        {
            template<typename E>
            std::wstring ToString(const std::vector<E> & t)
            {
                std::wstringstream result;
                result << L"Size: " << t.size();

                if (t.size())
                {
                    result << L", Elements: ";

                    for (const auto & element : t)
                    {
                        result << L"{ " << element << L" } ";
                    }
                }
                return result.str();
            }
        }
    }
}

对于失败的测试,您可以清楚地看到向量的大小及其包含的元素。为了您的目的,您可以使用:

namespace Microsoft
{
    namespace VisualStudio
    {
        namespace CppUnitTestFramework
        {
            template<typename E>
            std::wstring ToString(const std::vector<E> & t)
            {
                return L"Size: " + std::to_wstring(t.size());
            }
        }
    }
}