为什么我的编译器会将以下GetLength函数指针视为不明确的 伪代码:
size_t GetLength(char*);
size_t GetLength(wchar_t*);
struct ITEM { };
double GetLength(ITEM*);
CString GetInfo(ITEM * item, std::function<double (ITEM*)> fn)
{
... omitted for clarity
}
ITEM * item = new ITEM;
cout << GetInfo(item, GetLength); // <- ambiguous error
GetInfo只允许双返回+ ITEM *参数模式。那么为什么考虑(而不是丢弃)GetLength的两个基于字符串的变体?
答案 0 :(得分:11)
std::function<...>
的构造函数是模板,因为它必须能够支持任何类似函数的输入类型。没有单一的类型可以推断,所以你的重载都可以构造;直到稍后编译之后才会出现类型不匹配的错误。
你可以这样做:
GetInfo(item, static_cast<double(*)(ITEM*)>(GetLength));
明确地丢弃其他重载。
换句话说,这是不起作用的原因:
void foo(int);
void foo(void*);
struct bar
{
template <typename T>
bar(T f)
{
f(5);
}
};
bar b(foo);
即使bar
的构造函数体只能与void foo(int)
一起使用,
它希望支持f(5)
将起作用的任何函数,因此参数类型是模板化的。这允许任何函数在该位置工作,这意味着编译器无法推断出要使用的单个最佳重载。
我认为一种语言级别的解决方案是将重载设置为实际上是一个仿函数本身。那就是:
void foo(int);
void foo(void*);
template <typename T>
double foo(int, T);
命名foo
(如bar(foo)
或甚至只是foo(5)
)会产生此类型的实例:
struct __foo_overload_set // internal
{
// forwarders
void operator()(int __arg0) const
{
// where __foo0 is the zeroth overload, etc...
return __foo0(__arg0);
}
void operator()(void* __arg0) const
{
return __foo1(__arg0);
}
template <typename __Arg1>
double operator()(int __arg0, __Arg1&& __arg1) const
{
return __foo2(__arg0, std::forward<__Arg1>(__arg1));
}
// converters
typedef void(*__foo0_type)(int);
operator __foo0_type() const
{
return __foo0;
}
typedef void(*__foo1_type)(void*);
operator __foo1_type() const
{
return __foo1;
}
template <typename T>
struct __foo2_type
{
typedef void(*type)(int, T);
};
template <typename T>
operator typename __foo2_type<T>::type() const
{
return __foo2;
}
};
其中,可以自行调用,将在我们想要的上下文中编译。 (AFAIK,它没有引入任何尚未存在的含糊之处,尽管它完全没有经过测试。)
答案 1 :(得分:0)
你的牙套不匹配。这就是编译器无法理解你的原因
CString GetInfo(ITEM * item, std::function<double ITEM*> fn)