有条件地将mixin应用于接口,具体取决于虚拟方法的存在

问题描述

我有很多类似的界面。我有一个类模板,该模板可以实现这些接口并实现那些接口共有的大多数操作。结果,我在这些界面上使用了mixin。

不幸的是,其中一些接口缺少某些常用方法

struct Intf1
{
    virtual void f() = 0;
};

struct Intf2 {}; // Missing f.

我想应用混入

template <class T>
struct Mixin
    : public T
{
    virtual void f() override {};
};

对于基类,恰好是基类声明了混合方法覆盖的虚方法f。所以,基本上我正在寻找一些元编程技术

template <template <class> class Mixin,class T> using Magic = ...;

使得Magic<Mixin,Intf1>Mixin<Intf1>,而Magic<Mixin,Intf2>Intf2

目前,我正在使用单独的特征来检查基类中是否有可用的方法,但是此解决方案存在一些问题:

  • 我必须重申功能签名。
  • 我不确定该方法是否是虚拟方法(尽管看起来可以做到)。
  • 由于类型转换/常量性,我可能会尝试覆盖与我的方法签名不完全匹配的方法

我希望可能会有更好的解决方案。如果我的Mixin是导致替换失败的类,那么我将尝试执行以下操作:Godbolt

解决方法

不可能检测一个函数是否是虚函数。

但是如果T覆盖了Mixin的所有纯虚函数,则它可以工作:

#include <type_traits>

struct Intf1{
    virtual void f() = 0;
};

struct Intf2 {};

struct Intf3{
    virtual void f2() = 0;
};

template <class T>
struct Mixin : public T{
    virtual void f() {}; // don't mark 'override',it will break SFINAE.
};

template<template<typename>class MixIn,typename T,typename = void>
struct Applier{
    typedef T type;
};
template<template<typename>class MixIn,typename T>
struct Applier<MixIn,T,typename std::enable_if<std::is_abstract<T>::value && std::is_abstract<MixIn<T>>::value>::type>{
    typedef T type;
};
template<template<typename>class MixIn,typename std::enable_if<std::is_abstract<T>::value && !std::is_abstract<MixIn<T>>::value>::type>{
    typedef MixIn<T> type;
};

template<template<typename>class MixIn,typename T>
using applier_t = typename Applier<MixIn,T>::type;

static_assert(std::is_same<applier_t<Mixin,Intf1>,Mixin<Intf1>>::value,"overridden");
static_assert(std::is_same<applier_t<Mixin,Intf2>,Intf2>::value,"not abstract");
static_assert(std::is_same<applier_t<Mixin,Intf3>,Intf3>::value,"not overridden");