从指向成员的指针的模板推导,其中至少有一个指向成员的指针是已知的
Template deduction from pointer-to-members, where at least one pointer-to-member is known
考虑一个结构,其中包含接受指向成员的指针函数的静态方法模板。请注意,当方法的其中一个参数是实际的指向成员的指针函数时,可以推导出两个模板参数,无论另一个参数是否为nullptr
。
请参阅以下代码下面的问题:
struct Checker
{
template <typename T, typename V>
static void Check(
V(T::*getter)(),
void(T::*setter)(V)
);
template <typename T, typename V>
static void CheckDefault(
V(T::*getter)() = nullptr,
void(T::*setter)(V) = nullptr
);
};
struct Test
{
int Value();
void Value(int);
int Getter();
void Setter(int);
};
Checker::CheckDefault(&Test::Value); //1
Checker::CheckDefault(&Test::Value, nullptr); //2
Checker::Check(&Test::Value, nullptr); //3
Checker::CheckDefault(&Test::Getter); //4
Checker::CheckDefault(&Test::Getter, nullptr); //5
Checker::Check(&Test::Getter, nullptr); //6
- 为什么
&Test::Value
的正确过载可以在 1 中确定,而在 2 和 3 中却不能确定? - 为什么 1 和 4 能够推断出正确的类型名称,而 2、3、5 和 6 却不能?
>编辑我希望能够调用方法,并将两个参数中的至少一个设置为实际的指向成员函数,从而导致推导成功。这样:
Checker::Check(&Test::Value, &Test::Value); // Both getter and setter
Checker::Check(&Test::Value, nullptr); // Only getter
Checker::Check(nullptr, &Test::Value); // Only setter
<小时 />编辑
@Oliv解释为什么它不能按我的预期工作,在例外答案中的讨论为我指明了解决特定问题的正确方向。
我最终使用了转发器,正如@Ben Voigt所建议的那样。像这样:
template <typename T, typename V>
using GetterT = V(T::*)();
template <typename T, typename V>
using SetterT = void(T::*)(V);
template <typename T, typename V>
void Checker::CheckGetterAndSetter(
GetterT<T, V> getter,
SetterT<T, V> setter
)
{
// Do stuff with getter and setter.
}
template <typename T, typename V>
void Checker::CheckGetter(
GetterT<T, V> getter
)
{
SetterT<T, V> null = nullptr;
return CheckGetterAndSetter(getter, null);
}
template <typename T, typename V>
void Checker::CheckSetter(
SetterT<T, V> setter
)
{
GetterT<T, V> null = nullptr;
return CheckGetterAndSetter(null, setter);
}
TL;DR 它之所以成功,是因为默认参数不用于模板参数推断。在其他情况下(2,3,5,6),它失败了,因为nullptr_t
没有T(U::*)(V)
的形式(甚至没有T*
)。
让我们举一个更简单的例子:
template<class T>
void f(T,T*=nullptr);
int main(){
f(10,nullptr);// (1) error
f(10);// (2) OK
}
对于(1)编译器认为它应该能够从第一个参数和第二个参数中推断出T
,因为形式为T
或T*
的参数是免赔额。由于nullptr_t
不是T*
的形状,因此编译失败。
对于 (2),编译器仅对函数的第一个参数执行模板参数推导,因为默认参数在模板参数推导中不起作用。因此,它毫不含糊地推断出T
是int
。然后当调用该函数时,nullptr
将被转换为int*
。
相关文章:
- 从成员指针到整个结构/类的强制转换
- OOP 中的单成员指针
- 使用结构成员指针在C++中填充结构
- 聚合初始化,将成员指针设置为同一结构成员
- 空指针常量 (nullptr)、空指针值和空成员指针值之间有什么区别?
- 共享 C++ 的数据成员指针
- 如何声明指向成员内容的成员指针m_pmd/m_pmf并访问它们?
- 从类C++外部调用指向成员方法的成员指针
- 结构成员指针是否自动初始化为零?
- 如何删除类内类类型的类成员指针
- 是否打印指向已定义 int 的成员指针
- 指向常量的成员指针
- 通过此指针访问时的成员差异和自身的成员指针(简单的 QT 示例问题)
- 类数据成员指针的非类型模板参数包无法使用 gcc 编译
- 为什么我不能在同一行中定义两个相同类型的类的成员指针
- 将类成员指针传递给 Lambda 捕获列表 c++11
- 在单一实例类中将成员指针设置为 null 的正确方法是什么
- 无法删除在destructor中的成员指针的课程
- 删除对象而不调用成员指针的析构函数
- 当派生类的基类具有成员指针时,对其进行深层复制