为什么C++无法推断模板类型?

Why can't C++ infer the template type?

本文关键字:类型 C++ 为什么      更新时间:2023-10-16

为什么编译器不能找出这些模板参数?有办法让它这样做吗?

(我使用的是Visual Studio 2010)

template<typename T, typename TFunc>
void call(TFunc func) { func(T()); }
void myfunc(void *) { }
int main() { call(myfunc); }

T在参数列表中没有出现,因此不能从函数参数中推断出T。所有要推导的类型必须出现在参数列表中的推导上下文中。例如,

template <typename TReturn, typename TParameter>
void call(TReturn (*f)(TParameter))
{
    f(TParameter());
}

函数模板的模板形参推导只能基于函数实参,不能基于其他。函数定义永远不会被用来确定模板参数,所以你的参数T不可能被推导出来。

您可以通过将类型合并到函数签名中来纠正这种情况:由于您希望外部函数与函数本身一起调用,因此请明确:

template <typename T> void foo(void(*f)(T))
{
  T x;
  f(x);
  // ...
}

如果将函数重载与函子结合使用,一般情况下就不可能确定可以将哪些参数传递给可调用实体。

考虑,例如

struct FunctorExample {
    void operator()(int x) {...}
    std::string operator()(const std::string& ) {...}
};

如果有某种方法可以诱使编译器在参数上进行模式匹配,那么当应用于FunctorExample时,它必须具有未定义或错误行为。

相反,趋势似乎是当你想用函子模板元程序时,你指定函子和实参列表。例如boost::result_ofboost::fusion

编辑:也就是说,如果你愿意稍微限制你的注意力,并且你可以使用一些c++ 11语法(decltype),你可以安排更多的内省:

// Support functors with a very simple operator():
template <typename T> struct argument :
    public argument<decltype(&T::operator())> {};
// Pointers to member functions
template <typename C, typename R, typename A> struct argument<R(C::*)(A)>
    {typedef A type;};
// Function types
template <typename R, typename A> struct argument<R(A)> {typedef A type;};
// Function pointer types.
template <typename R, typename A> struct argument<R(*)(A)> {typedef A type;};
// Now for call:
template <typename FuncType>
void call(FuncType func) { 
    typedef typename argument<FuncType>::type Arg;
    func(Arg());
}
// example:
class FunctorInt {public: int operator()(int ) {return 0;};};
void myfunc(void *) {}
int main() {
    call(myfunc);
    call(FunctorInt());
}
可变模板可用于扩展此内容以支持多个参数。