模板重载解决问题

时间:2016-04-29 22:12:11

标签: c++ templates c++03 overload-resolution c++98

鉴于此代码:

#include <string>
#include <vector>
#include <iostream>

template <typename T>
std::string stringify(const T&) {
    return "{?}";
}

template <typename T>
std::string proxy(const T& in) {
    return stringify(in);
}

// trying to specialize "stringify()"

template <typename T>
std::string stringify(const std::vector<T>& in) {
    return "vector specialization!";
}

template <>
std::string stringify(const std::vector<int>& in) {
    return "INT vector specialization!";
}

int main() {
    std::cout << proxy(1); // calls the 1st

    std::vector<int> intVec;
    std::cout << proxy(intVec); // calls the 1st

    std::vector<double> dblVec;
    std::cout << proxy(dblVec); // calls the 1st

    return 0;
}

如何在stringify()之后为vector<>专门化proxy<>

目前我得到{?}{?}{?}

如果我删除了这个 - stringify(const std::vector<T>& in),则vector<int>开始被调用,因为它将是第一个的专门化。

然后我会得到{?}INT vector specialization!{?}

有没有办法调用proxy()中的2个向量特化字符串化函数中的任何一个 - 如果它们是最后定义的 - 在proxy()函数之后?

有没有办法部分专注于vector<>,仍然可以从proxy<>调用?

我不想专注于vector<int>vector<double>vector<UserType> ......

编辑:忘记提及C++98

我需要这个

1 个答案:

答案 0 :(得分:3)

首先,避免专门化功能模板,更喜欢重载。有关潜在的陷阱,请参阅Herb Sutter's article

其次,您遇到的问题涉及名称查找如何在函数模板中为依赖名称工作。在proxy<T>内,stringify是一个从属名称 - 它取决于T。该名称将在模板定义点(将查找stringify<T>(const T&)而不是其他重载)中查找,并再次在参数的关联命名空间中实例化时({{1} }})。这些查找都没有找到您的其他功能。

这是我们可以利用的查找的第二部分 - 依赖于参数的查找。让我们把所有东西都放在一个命名空间中(我任意命名std,随意重命名):

N

好的,到目前为止,我们完全没有改变。在所有情况下,我们仍会获得namespace N { struct helper { }; template <typename T> std::string stringify(helper, const T&) { return "{?}"; } } template <typename T> std::string proxy(const T& in) { return stringify(N::helper(), in); } 。但是现在我们可以在{?}的定义之后仍然在stringify中继续{strong>重载(非专业化)proxy

namespace N {    
    template <typename T>
    std::string stringify(helper, const std::vector<T>& ) {
        return "vector overload!";
    }

    std::string stringify(helper, const std::vector<int>& ) {
        return "INT vector overload!";
    }
}

这两个重载将在名称查找的第二阶段找到,因为Nhelper的关联命名空间。现在proxy(intVFec)将找到stringify的所有三个重载,而不仅仅是一个。{1}}。现在您的代码打印出来了:

{?}INT vector overload!vector overload!

根据需要。以上都不需要C ++ 11。