AnA*_*ons 6 c++ member-function-pointers language-lawyer
所以我有这样一个场景,我想调用一个类的任何一个函数,其中有问题的函数具有相同的原型,但它也被重载了。因为我知道指向成员的指针,所以我的直接反应是这样的:
struct test
{
    int overloaded(char) {}
    int overloaded(int) {}
    int overloadedone(char) {}
    int overloadedone(int) {}
} test;
int main()
{
    (test.*(true ? (&test::overloaded) : (&test::overloadedone)))(1);
}
然而事实证明编译器(MSVC - 2019 Preview 最新版本与 std C++ 预览版)无法推断类型,我必须写:
(test.*(true ? static_cast<int (test::*)(int)>(&test::overloaded) : static_cast<int (test::*)(int)>(&test::overloadedone)))(1);
相反,这让我回到了过去:
true ? test.overloaded(1) : test.overloadedone(1);
但我想知道这是否是要求这些演员的定义行为。甚至:
(test.*static_cast<int (test::*)(int)>(true ? (&test::overloaded) : (&test::overloadedone)))(1);
不起作用。
您必须像第二个示例中那样针对三元的两种可能性中的每一种编写上述转换。
它不是特别优雅,但如果在传递成员函数指针本身之前对成员函数指针的参数进行柯里化,则这种方法可以推断出重载:
#include <iostream>
template <class... Args>
auto invoke_conditional_mem_fn(Args... args)
{
    return [=] <class R, class X> (X x, bool b, R(X::*t)(Args...), R(X::*f)(Args...)) -> R
    {
        return (x.*(b ? t : f))(args...);
    };
}
struct test
{
    int overloaded(char) { std::cout << "overloaded(char) "; return 1; }
    int overloaded(int) { std::cout << "overloaded(int) "; return 2; }
    int overloadedone(char) { std::cout << "overloadedone(char) "; return 3; }
    int overloadedone(int) { std::cout << "overloadedone(int) "; return 4; }
} test;
int main()
{
    std::cout
        << invoke_conditional_mem_fn('1')(test, true, &test::overloaded, &test::overloadedone)
        << std::endl
        << invoke_conditional_mem_fn(1)(test, false, &test::overloaded, &test::overloadedone)
        << std::endl;
}
感谢@dyp和他们的例子,我们知道如果我们选择要传递的参数,我们可以推断出成员函数指针的返回类型和基数。
或者,如果满足您的需求,您可以做一些更简单的事情。if只需声明一个 lambda 即可使用and语句解决三元表达式的限制else,因为三元运算符的每个分支都必须具有相同的类型。
#include <iostream>
struct test
{
    int overloaded(char) { std::cout << "overloaded(char) "; return 1; }
    int overloaded(int) { std::cout << "overloaded(int) "; return 2; }
    int overloadedone(char) { std::cout << "overloadedone(char) "; return 3; }
    int overloadedone(int) { std::cout << "overloadedone(int) "; return 4; }
} test;
auto conditional = [] (struct test& test, bool cond, auto... args)
{
    if (cond) return test.overloaded(args...);
    else return test.overloadedone(args...);
};
int main()
{
    std::cout << conditional(test, true, '1') << std::endl;
    std::cout << conditional(test, false, 1) << std::endl;
}