我有一个带有init()方法的模板类,如果它存在,必须调用子类方法。 Base类的方法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()方法,它可以是任何。
答案 0 :(得分: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)...);
}
我们在哪里创建帮助器类,可以是sink
,也可以转发到init
,具体取决于对init
的调用是否有效。
我们最终不得不做这样的事情,因为除非T::init
已经有方法T
,否则您无法将令牌init
命名为有效。因此,我们必须编写一个自定义类,在SFINAE上下文中执行T::init
查找,如果失败则回退到什么都不做。