模板重载解决问题
template overload resolution trouble
鉴于此代码:
#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!{?}
有没有办法从 proxy()
调用任何 2 个向量专业化字符串化函数 - 如果它们是最后定义的 - 在 proxy()
函数之后?
有没有一种方法可以部分专注于 vector<>
并且仍然可以从 proxy<>
调用?
我不想专攻 vector<int>
、vector<double>
、vector<UserType>
...
编辑: 忘了说我需要这个 C++98
首先,避免特化函数模板,更喜欢重载。请参阅 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);
}
好的,到目前为止我们完全没有改变任何东西。在所有情况下,我们仍然得到 {?}
。但是现在我们可以进一步 overloads (不是特化) stringify
仍然在那个命名空间中但是在 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!";
}
}
这两个重载将在名称查找的第二阶段找到,因为 N
是 helper
的关联命名空间。现在 proxy(intVFec)
将找到 stringify
的所有三个重载,而不仅仅是一个。现在您的代码打印:
{?}INT vector overload!vector overload!
随心所欲。 None 以上需要 C++11。
鉴于此代码:
#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!{?}
有没有办法从 proxy()
调用任何 2 个向量专业化字符串化函数 - 如果它们是最后定义的 - 在 proxy()
函数之后?
有没有一种方法可以部分专注于 vector<>
并且仍然可以从 proxy<>
调用?
我不想专攻 vector<int>
、vector<double>
、vector<UserType>
...
编辑: 忘了说我需要这个 C++98
首先,避免特化函数模板,更喜欢重载。请参阅 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);
}
好的,到目前为止我们完全没有改变任何东西。在所有情况下,我们仍然得到 {?}
。但是现在我们可以进一步 overloads (不是特化) stringify
仍然在那个命名空间中但是在 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!";
}
}
这两个重载将在名称查找的第二阶段找到,因为 N
是 helper
的关联命名空间。现在 proxy(intVFec)
将找到 stringify
的所有三个重载,而不仅仅是一个。现在您的代码打印:
{?}INT vector overload!vector overload!
随心所欲。 None 以上需要 C++11。