模板参数不明确:无法推断模板参数

Hir*_*aCC 9 c++ templates ambiguous ambiguous-call template-argument-deduction

我正在做一些看起来像这样的包装器:

#include <iostream>

template<class T, class Value>
void Apply(void (T::*cb)(Value), T* obj, Value v)
{
    (obj->*cb)(v);
}

class Foo
{
public:
    void MyFunc(const int& i)
    {
        std::cout << i << std::endl;
    }

    const int& GetValue()
    {
        return i_;
    }

private:
    int i_ = 14;
};

int main()
{
    Foo f;
    Apply(&Foo::MyFunc, &f, f.GetValue());
}
Run Code Online (Sandbox Code Playgroud)

我收到这个错误:

  • Apply:找不到匹配的重载函数.
  • void Apply(void (__thiscall T::* )(Value),T *,Value):模板参数Value不明确,可能是intconst int &.
  • void Apply(void (__thiscall T::* )(Value),T *,Value):无法推断Valuefrom的模板参数const int.

所以我得到它来自模板参数推导,但我不明白如何.为什么Value 评估const int&两次?

Bar*_*rry 13

为什么失败

目前,模板参数Value在调用中的两个不同位置推导出Apply:从指针到成员函数参数和从最后一个参数.从&Foo::MyFunc,Value推断为int const&.从f.GetValue(),Value推断为int.这是因为为了模板推断而删除了引用和顶级cv限定符.由于参数的这两个推论Value不同,因此推论失败 - Apply()从过载集中删除,因此我们没有可行的过载.

如何解决它

问题是Value在两个不同的地方推断出来,所以让我们来防止这种情况发生.一种方法是在非推导的上下文中包含其中一个用法:

template <class T> struct non_deduced { using type = T; };
template <class T> using non_deduced_t = typename non_deduced<T>::type;

template<class T, class Value>
void Apply(void (T::*cb)(Value), T* obj, non_deduced_t<Value> v)
{
    (obj->*cb)(v);
}
Run Code Online (Sandbox Code Playgroud)

最后一个参数v是类型non_deduced_t<Value>,顾名思义,它是一个非推导的上下文.因此,在模板推导过程中,从指向成员函数的指针(如前所述)Value推导出来int const&,现在我们只需将其插入到类型中即可v.

或者,您可以选择推导cb为自己的模板参数.在这一点上Apply()只减少到std::invoke().