指向模板参数中重载函数的MSVC指针
MSVC pointer to overloaded function in template parameter
我已经在一个问题上徘徊了至少两周,被我无法理解的东西挡住了去路,并在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中编译的(我很震惊,通常是opsite,因为MSVC的标准不那么严格)。
问题的根源是,我的SFINAE方法在MSVC下编译时未能检测到方法set::insert
,为了寻找这个失败,我写了一个简单的测试:
#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
的声明会编译;但是具有与模板参数相同的签名却没有。这就是为什么在SFINAE的符号替换期间CCD_ 5检测失败的原因。错误文本cannot convert from 'overloaded-function'
没有为我提供任何关于发生了什么的线索(或者由于我的英语理解能力差,我找不到任何线索)。
乍一看,我一直认为问题在于符号替换,但如果它在MSVC和gcc中都失败了,那就有意义了。所以现在我想知道问题是否是MSVC编译器特定的方法。
关于它为什么在MSVC下失败,以及如何使gcc和MSVC以相同的方式工作,有什么线索吗
额外的问题:std::map
和std::set
在红黑树的MSVC实现下(或者map
和set
下的任何东西)为::insert
方法提供了嵌套类型_Pairib
作为返回类型,在gcc实现中没有等价的?
编辑:
在阅读了冷静的答案之后,我研究了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));
}
这个插入方法属于std::_Tree
作用域,而不是std::set
作用域,但它属于公共作用域,也是一个继承的方法,所以为什么在名称替换过程中它不可访问
失败的原因是在VC stdlib中,insert
实际上不是set
类模板本身的成员,而是继承的:
测试用例,
template
<
typename Type,
typename Return,
typename Parameter,
Return (Type::*)(Parameter)
> struct W {};
struct A { void foo (int); };
struct B : public A {};
int main(int argc, char **argv)
{
void (B::*p)(int) = &B::foo;
// W<B, void, int, &B::foo> w; // error
W<A, void, int, &A::foo> w;
return 0;
}
PS。该错误在某些GCC和某些MSVC中都是错误。
但它在公共范围内,也是一个继承的方法,所以我不明白为什么它不可访问。
因为在这种情况下不允许转换,"14.3.2。模板非类型参数[#5]">
对于指向成员函数的指针类型的非类型模板参数,如果模板参数的类型为std::nullptr_t,则null成员应用指针转换(4.11)否则,不应用任何转换。如果模板参数表示一组重载成员函数,从集合中选择匹配的成员函数(13.4).
PPS。所以,你显式地进行转换,瞧,你不需要关心可能的基类:
W<setint,
std::pair<setint::iterator, bool>,
const setint::value_type &,
static_cast<std::pair<setint::iterator, bool> (setint::*)(const setint::value_type &)> (&setint::insert)> w_1;
根据这个问题,Standard没有定义您可以将成员函数指针指向Standard对象的成员。
_Pairib
是一个MSVC实现细节——当然在GCC中找不到类似的东西。
- C++17中函数模板中的静态数组初始化(MSVC 2019)
- std::vector::p ush_back() 不会在 MSVC 上编译具有已删除移动构造函数的对象
- MSVC 和函数参数的 constexpr?
- constexpr 函数的常量引用参数:gcc/msvc vs clang/icc
- MSVC 2017 - 错误 - 如何将模板类 X 的模板成员函数声明为嵌套类 X::Y 的好友
- 将内联程序集尾调用函数尾声替换为用于x86/x64 msvc的Intrinsics
- 为什么 MSVC 在使用正确的签名覆盖函数时会产生 C3668 错误?
- std::value templated 方法的函数使用 clang 和 g++ 进行编译,但不使用 msvc 进行编译
- 继承基构造函数,基类是模板参数 (MSVC)
- constexpr 函数中的 for 循环无法使用 MSVC 19.23 进行编译
- MSVC 编译器/链接器何时合成标量/矢量删除析构函数
- x64 函数调用参数推送/移动顺序 (MSVC)
- C++具有可变参数包的函数的部分模板参数推导会在 Clang 和 MSVC 中产生不明确的调用
- enable_if is_same constexpr函数使MSVC失败(但在Clang,GCC中效果很好)
- MSVC:带函数的"error C2244: unable to match function definition to an existing declaration"是指专用模板类的类型别名
- MSVC 无法识别继承模板类的模板类的"直接"基类构造函数
- MSVC 2017 在共享库中创建模板函数的副本
- MSVC 在不应该调用时内联虚拟函数调用
- 已删除的构造函数 - MSVC 报告错误,Clang 不报告
- 在__device__函数(MSVC)中找不到CUDA copyign()函数