Consider a struct with static method templates that accept pointer-to-member functions. Note that when one of the arguments to the methods is an actual pointer-to-member function, both template parameters can be deduced, regardless if the other argument is a nullptr
or not.
See questions below the following code:
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
- Why can the correct overload of
&Test::Value
be determined in 1, but not in 2 and 3? - Why are 1 and 4 able to deduce the correct typenames, but 2, 3, 5 and 6 not?
Edit
I was expecting to be able to call the methods with at least one of the two arguments set to an actual pointer-to-member function, causing deduction to succeed. Like so:
Checker::Check(&Test::Value, &Test::Value); // Both getter and setter
Checker::Check(&Test::Value, nullptr); // Only getter
Checker::Check(nullptr, &Test::Value); // Only setter
Edit
The discussion in the excepted answer by @Oliv explaining why it doesn't work as I expected, pointed me in the right direction for solving my specific problem.
I ended up using forwarders, as @Ben Voigt suggested. Something like:
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);
}