我使用vs14编译器的函数模板有问题。 所以下面的代码演示了这个问题。
#include <iostream>
using namespace std;
class Class {
public:
int memberFoo() {
return 0;
}
};
template <class VariableT, class C>
void nothing(const VariableT C::*memberV) {
cout << "Pointer to member variable";
}
template <class R, class C>
void nothing(R (C::*memberF)()) {
cout << "Pointer to member function";
}
int main() {
nothing(&Class::memberFoo);
return 0;
}
编译器让我知道nothing
函数含糊不清。当我看到输出时,它似乎有其他行为超出我的预期。
在第一个nothing
函数中,编译器将VariableT
推导为int(void)
。实际上并不奇怪,但我认为第二个更合适并且会匹配。更有意思的是,如果在第一个重载函数中删除const
,程序将正确编译。
你能建议我怎么处理这个吗?
答案 0 :(得分:6)
您可以使用一些方便的type_traits is_member_function_pointer和is_member_object_pointer来修复它:
template <class R, class C>
void nothing(R (C::*memberF)())
{
std::cout << "Pointer to function" << std::endl;
}
template <class VariableT, class C>
auto nothing(const VariableT C::* memberV)-> typename std::enable_if<std::is_member_object_pointer<decltype(memberV)>::value>::type
{
cout << "Pointer to member variable";
}
std::enable_if
的默认类型为void
,因此返回类型仍为void
。
从你的帖子看起来听起来应该实例化成员函数模板,但是Visual Studio和Clang都对模糊性大喊大叫,我认为这是公平的,给定Type Class::*
,你可以推断出一个指向成员或指针的指针成员函数,假设ReturnType()
的替换对Type
有效(这是我们正在看到的)。
所以我决定跳过所有这些并利用尾随返回类型直接询问参数。
在link
中加入T.C.'s comment中的文字章节:14.8.2.1 [temp.deduct.call]
目前尚不清楚以下是否形成良好:void foo(){} template<class T> void deduce(const T*) { } int main() { deduce(foo); }
实施方案对此示例的处理方式各不相同。
确实,您注意到删除const
也消除了歧义。