2016-04-29 138 views
2

鉴于此代码:模板重载麻烦

#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; 
} 

我怎样才能proxy<>后专门为stringify()vector<>

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

如果我删除这一个 - stringify(const std::vector<T>& in)那么vector<int>开始变得调用,因为这将是第一的专业化。

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

有什么办法调用任何的2矢量专业化字串功能从proxy() - 如果它们被定义最后 - 在proxy()功能之后?

有没有办法部分专注于vector<>并仍然从proxy<>打电话?

我不想专门为vector<int>vector<double>vector<UserType> ...

编辑:忘了提我需要这个C++98

回答

3

首先,避免专业函数模板,更喜欢超载。有关潜在隐患,请参阅Herb Sutter's article。其次,您遇到的问题涉及名称查找如何在函数模板中为从属名称起作用。里面proxy<T>stringify是一个独立的名字 - 它取决于T。该名称将在模板的定义点(它将找到stringify<T>(const T&)而不是其他重载)和在参数的相关名称空间(将是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); 
} 

好了,到目前为止,我们已经改变绝对没有。在所有情况下我们仍然得到{?}。但现在我们仍然可以在该命名空间但proxy定义后的stringify坚持进一步重载(不是特例):

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!"; 
    } 
} 

这两个重载将通过名称查找,因为N的第二阶段中找到是一个关联的命名空间helper。现在proxy(intVFec)将找到stringify的所有三种重载,而不仅仅是一种。现在您的代码打印:

{?}INT vector overload!vector overload! 

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

+0

非常感谢!你救了我的屁股!我喜欢它,当C++魔术工作,我不明白它 - 仍然试图不学习ADL :)生命是短暂的。 – onqtam

+0

@onqtam ADL是非常重要的 - 毕竟它是如何'标准:: cout <<“你好,世界!”'工作! – Barry

+0

刚刚发现,这不能在VC++ 6下编译...也许ADL是坏的(只有当使用模板重载!免费函数重载罚款) - 它说在'''代理()'''如果有超过1个专业化,该调用是不明确的。也许是时候放弃对它的支持 – onqtam