如何从C ++模板中的方法类型推导出类类型?

时间:2010-09-30 12:34:14

标签: c++ templates generics traits

在如下所示的模板中,我希望调用Run(&Base::foo)成功,而无需将Base类型命名两次(如编译Run<Base>(&Base::foo)调用中所做的那样)。我可以吗?可能没有添加大量Boost标题?

使用提供的代码,我收到错误:

prog.cpp:26: error: no matching function for call to ‘Run(bool (Base::*)())’

(你可以在http://ideone.com/8NZkq)摆弄片段:

#include <iostream>

class Base {
public:
  bool foo() { return true; }
};

Base* x;

template<typename T>
struct Traits {
  typedef bool (T::*BoolMethodPtr)();
};

template<typename T>
void Run(typename Traits<T>::BoolMethodPtr check) {
  T* y = dynamic_cast<T*>(x);
  std::cout << (y->*check)();
}

int main() {
  Base y;
  x = &y;
  Run<Base>(&Base::foo);
  Run(&Base::foo); // why error?
}

4 个答案:

答案 0 :(得分:9)

T中的Traits<T>::BoolMethodPtr处于非推导的上下文中,因此编译器不会自动从调用中推断出T应该是什么类型。 这是因为可能有这样的代码:

template<typename T>
struct Traits {
  typedef bool (T::*BoolMethodPtr)();
};

template<>
struct Traits<int> {
  typedef bool (Base::*BoolMethodPtr)();
};

Run(&Base::foo); /* What should T be deduced to? Base and int are both equally possible */

如果您没有Traits<T>课程,可以将Run写为:

template<class Class>
void Run(bool (Class::*check)()) {
  Class* y = dynamic_cast<Class*>(x);
  std::cout << (y->*check)();
}

在此背景下,Class可以推断为Base

答案 1 :(得分:4)

要分离类型,任何类型,请使用部分特化。没有函数模板部分特化,所以你需要在其参数类型上直接参数化函数并检索里面的类类型。

template< typename T >
struct get_host_class; // most types are not ptmfs: don't implement this

template< typename C >
struct get_host_class< bool (C::*)() > { // implement partial specialization
     typedef C host;
     typedef void sfinae; // disallow function for non ptmf arguments
};

template< typename T >
typename get_host_class<T>::sfinae Run( T check) {
    typedef T BoolMethodPtr; // or something
    typedef typename get_host_class< T >::host host;
}

答案 2 :(得分:2)

我认为这是一个非演绎的背景。

  

$ 14.8.2.5 / 5-“未推断的背景   是: - a的嵌套名称说明符   使用a指定的类型   合格-ID“。

我认为这是适用于这种情况的引用。但是一些模板神需要批准我的理解。

答案 3 :(得分:2)

当编译器尝试匹配模板参数时,它只考虑主类类型。换句话说,当它遇到表达式时:

Run(&Base::foo);

...它试图找出Run的模板参数,它只考虑foo本身的类型,并不考虑任何类foo是一个部分的。

编辑:

foo的类型是bool(Base::*)(void),但您希望编译器找到的只是Base