4

我有一个带有 init() 方法的模板类,如果存在则必须调用子类方法。基类的方法 init() 永远调用。

template <class T>
class Base
{

   template<typename... Args>
   void init(Args... args);

   T subj;

   explicit Base() { subj = new T(); }
}


template<typename... Args>
Base<T>::init(Args... args)
{
    invoke_if_exists<&T::init,subj>(args); // <-- that moment
}

需要实现 invoke_if_exists 模板。算法应该是这样的代码

if ( method_exists(T::init) )
{
     subj->init(Args...);
}   

我需要将它包装到模板中

太感谢了。

[更新]:

让我试着解释一下。

class Foo
{
// ... and there is no init()
};

class Right
{
    void init() { ... }
 /// ...
}


auto a = new Base<Foo>();
auto b = new Base<Right>();

a->init();  // there is no call for Foo::init();
b->init();  // there is correct call for Right::init();

invoke_if_exists<>不仅想与 init() 方法一起使用,它可以是任何方法。

4

1 回答 1

3

一个数据和类型接收器,它接受类型和数据,并且对它们不做任何事情:

struct sink {
  template<typename... Us>
  void operator()(Us&&... us) const {}
};
template<typename... Ts>
struct type_sink:std::true_type {};

然后我们创建一个template invoke_init_if_exists,它接受一个目标类型T和一组参数,如果T*->init可以用这些参数调用,就这样做。否则,它将这些东西扔到上面的数据接收器中:

template<typename T,typename ArgTypes,typename=void>
struct invoke_init_if_exists:sink {};
template<typename T,template<typename...>class Pack,typename... Args>
struct invoke_init_if_exists<T,
  Pack<Args...>,
  typename std::enable_if< type_sink<
    decltype( std::declval<T*>()->init( std::declval<Args>()... ) )
  >::value >::type
>
{
  void operator()( T* target, Args&&... args ) const {
    target->init( std::forward<Args>(args)... );
  }
};

然后我们用它来实现你的init方法:

template<typename... Args>
Base<T>::init(Args&&... args)
{
  invoke_init_if_exists<T, type_sink<Args...>>()(&subj, std::forward<Args>(args)...);
}

我们在哪里创建我们的助手类,它可以是 asink或转发到的东西,init具体取决于调用init是否有效。

我们最终不得不做这样的事情,因为除非已经有一个方法,否则你不能T::init用有效性命名令牌。因此,我们必须编写一个自定义类,在 SFINAE 上下文中进行查找,如果失败则回退到什么都不做。TinitT::init

于 2013-11-13T18:51:31.180 回答