我已经在一个问题上徘徊了至少两个星期,被我无法理解的东西所阻碍,并且在 SO 中提出的问题并没有真正指出真正的问题(我真傻!)。最后,我希望我能在这个问题中找到我头痛的真正点。
我一直在使用模板结构作为帮助器来检测给定类型是否具有成员方法,这个模板结构如下所示:
template
<
typename Type,
typename Return,
typename Parameter,
Return (Type::*)(Parameter)
> struct W {};
围绕的主要思想struct W
是将成员函数指针作为第四个参数,该指针指向我需要使用 SFINAE 技巧测试的成员函数,在上一个问题中提出了一个替代方案,它帮助我理解了我已经了解的许多概念一直失踪,但最终,它并没有解决我真正的问题。
我正在处理的代码必须在 Linux 和 Windows 平台上都可以工作,我用于 Windows 的编译器是 Linux 端的 MSVC(Visual Stuido 2010 10.0)和 gcc(Devian 4.4.5-8)。问题是同一段代码不能在 MSVC 中编译,但在 gcc 中可以编译(我很震惊,通常是相反的,因为 MSVC 的标准不那么严格)。
问题的根源是我的 SFINAE 方法set::insert
在 MSVC 下编译时无法检测到该方法,为了查找此失败,我编写了一个简单的测试:
#include <set>
int main(int argc, char **argv)
{
typedef std::set<int> setint;
std::pair<setint::iterator, bool> (setint::*p_1)(const setint::value_type &) = &setint::insert;
W<setint, std::pair<setint::iterator, bool>, const setint::value_type &, &setint::insert> w_1;
return 0;
}
正如我之前提到的:这个示例使用 gcc 编译没有问题,但是在使用 MSVC 时,在声明时会出错w_1
:
error C2440: 'specialization' : cannot convert from 'overloaded-function' to 'std::pair<_Ty1,_Ty2> (__thiscall std::set<_Kty>::* )(const int &)'
with
[
_Ty1=std::_Tree_const_iterator<std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>>,
_Ty2=bool,
_Kty=int
]
None of the functions with this name in scope match the target type
在创建函数指针时按预期工作,因此p_1
编译声明;但与模板参数具有相同的签名没有。这就是set::insert
在 SFINAE 的符号替换期间检测失败的原因。错误文本cannot convert from 'overloaded-function'
没有为我提供任何关于正在发生的事情的线索(或者由于我的英语理解不佳,我无法找到任何线索)。
乍一看,我一直认为问题出在符号替换上,但如果它在 MSVC 和 gcc 中都失败了,这将是有意义的。所以现在我想知道问题是否是一些特定于 MSVC 编译器的做事方式。
关于为什么它在 MSVC 下失败以及如何使 gcc 和 MSVC 以相同方式工作的任何线索?
额外的问题:std::map
andstd::set
提供了一个嵌套类型作为红黑树的 MSVC 实现下的方法的_Pairib
返回类型(或任何在and下的方法),在 gcc 实现中没有等价物吗?::insert
map
set
编辑:
在阅读了寒冷的答案后,我研究了 MSVC 的std::set
实现。
std::set
std::_Tree
是提供我要检查的方法的派生类:
// class std::_Tree, file xtree in the path 'VisualStudioPath/VC/include/'
_Pairib insert(const value_type& _Val)
{ // try to insert node with value _Val, favoring right side
return (insert(_Val, false));
}
这个insert方法属于std::_Tree
作用域,不属于std::set
作用域,但属于公共作用域,也是继承的方法,为什么在名称替换时不能访问呢?