C++ 根据类创建时的模板参数更改类API

C++ 根据类创建时的模板参数更改类API,c++,c++11,templates,sfinae,C++,C++11,Templates,Sfinae,我想创建一个类,在特定的模板实例化下,它将公开一个不同的API。它具有常见的函数,但如果用户将使用类的特定实例化,则应禁用一些函数。大概是这样的: VarApi<T1> v1; v1.common(); v1.funcA1(); // v1.funcA2(); // ERROR v1.funcA1_2(); VarApi<T2> v2; v1.common(); // v2.funcA1(); // ERROR v2.funcA2(); v2.funcA1_2();

我想创建一个类,在特定的模板实例化下,它将公开一个不同的API。它具有常见的函数,但如果用户将使用类的特定实例化,则应禁用一些函数。大概是这样的:

VarApi<T1> v1;
v1.common();
v1.funcA1();
// v1.funcA2(); // ERROR
v1.funcA1_2();

VarApi<T2> v2;
v1.common();
// v2.funcA1(); // ERROR
v2.funcA2();
v2.funcA1_2();

VarApi<T3> v3;
v3.common();
// v2.funcA1(); // ERROR
// v2.funcA2(); // ERROR
// v1.funcA1_2(); // ERROR
enum Type { T1, T2, T3 };

template <Type TType> struct VarApi {
    void common() { }

    template <Type T = TType,
        typename = typename std::enable_if<T == T1>::type>
    void funcA1() { }

    template <Type T = TType,
        typename = typename std::enable_if<T == T2>::type >
    void funcA2() { }

    template <Type T = TType,
        typename = typename std::enable_if<T == T1 || T == T2>::type >
    void funcA1_2() { }

    template <Type T = TType,
        typename = typename std::enable_if<T == T3>::type >
    void funcA3() { }
};
这可以工作并实现上述功能。问题在于,用户仍然可以通过以下方式覆盖此选项:

VarApi<T2> v2;
v2.funcA1<T1>(); // NOT ERROR
VarApi<T2> v2;
v2.funcA1<T1>(); // NOT ERROR
VarApi v2;
v2.funcA1();//不出错

有没有办法防止这种情况发生?您可以利用继承来提供所需的功能。使用CRTP,您可以通过
self
指针在
func\u提供程序中访问原始类的功能

template<class T, class Derived> struct func_provider;

template<class Derived>
struct func_provider<int, Derived> {
    void funcA1() {
        auto self = static_cast<Derived*>(this);

        // do something with self
    }
};
template<class Derived> struct func_provider<double, Derived> { void funcA2() {} };

template<class T>
struct foo : public func_provider<T, foo<T>> {};

int main() {
    foo<int> f;
    foo<double> g;
    f.funcA1();
    // f.funcA2(); // Error
    g.funcA2();
    // g.funcA1(); // Error
}
模板结构函数提供程序;
模板
结构函数提供程序{
void funcA1(){
自动自=静态施法(本);
//自作主张
}
};
模板结构func_提供程序{void funcA2(){};
模板
struct foo:public func_provider{};
int main(){
福福;
傅g,;
f、 funcA1();
//f.funcA2();//错误
g、 funcA2();
//g.funcA1();//错误
}
编辑:

此版本允许用户在一个位置实现多种类型的功能,用户可以将各种类型组合在一起:

template<class... Ts> struct types {};

template<class Types, class T> struct is_in : public std::false_type {};
template<class... Ts, class T>
struct is_in<types<T, Ts...>, T> : public std::true_type {};
template<class... Ts, class T0, class T>
struct is_in<types<T0, Ts...>, T> : public is_in<types<Ts...>, T> {};

template<class Derived, bool B, class T> struct func_provider {};
template<class Derived, class T, class... Ts>
struct func_collector
    : public func_provider<Derived, is_in<Ts, T>::value, Ts>...
{};


// implement functions for int
template<class Derived>
struct func_provider<Derived, true, types<int>> {
    void funcA1() {
        auto self = static_cast<Derived*>(this);
        // do something with self
    }
};

// implement functions for double
template<class Derived>
struct func_provider<Derived, true, types<double>> { void funcA2() {} };

// implement functions for both int and double
template<class Derived>
struct func_provider<Derived, true, types<int, double>> { void funcA1_2() {} };

template<class T>
struct foo : public func_collector<foo<T>, T,
    // pull desired functions
    types<int>, types<double>, types<int, double>>
{
    void common() {}
};

int main() {
    foo<int> f;
    foo<double> g;
    f.common();
    f.funcA1();
    f.funcA1_2();
    // f.funcA2(); // Error
    g.funcA2();
    g.funcA1_2();
    // g.funcA1(); // Error
}
模板结构类型{};
模板结构是_in:public std::false_type{};
模板
结构是_in:public std::true_type{};
模板
struct is_in:public is_in{};
模板结构函数提供程序{};
模板
结构函数收集器
:公共函数提供程序。。。
{};
//为int实现函数
模板
结构函数提供程序{
void funcA1(){
自动自=静态施法(本);
//自作主张
}
};
//实现双线程的功能
模板
结构func_提供程序{void funcA2(){};
//实现int和double函数
模板
结构函数提供程序{void funcA1_2(){};
模板
struct foo:公共函数收集器
{
void common(){}
};
int main(){
福福;
傅g,;
f、 普通();
f、 funcA1();
f、 函数1_2();
//f.funcA2();//错误
g、 funcA2();
g、 函数1_2();
//g.funcA1();//错误
}
解决方案1 实现所需功能的一种方法是使用tempalte专门化和依赖基类来提供可选功能

// I'm using E for enum. I find TType a bit misleading, since T usually stands for Type
template< Type EType > 
struct VarApiBase { }; // empty by default

template< >
struct VarApiBase<T1> {
  void funcA1() { }
};

template< >
struct VarApiBase<T2> {
  void funcA2() { }
};

template <Type TType>
struct VarApi : VarApiBase<TType> {
  void funcA1_2() { }
};

template <>
struct VarApi<T3> { };
如果确实需要SFINAE,仍然可以将
==T1 | |==T2
条件放在模板中

template <Type ETypeInner = EType,
  typename = typename std::enable_if<ETypeInner == T1 || ETypeInner == T2>::type >
void funcA1_2() {
  static_assert(ETypeInner==EType);
}
例如,如果您有一个funcA2_3,您仍然可以这样做:

struct VarApiCommon {
  void common();
};

struct VarApi12 : virtual VarApiCommon {
  void funcA1_2();
};

struct VarApi23 : virtual VarApiCommon {
  void funcA2_3();
};

template< Type EType >
struct VarApi; // undefined

template<>
struct VarApi<T1> : VarApi12 {
  void funcA1();
};

template<>
struct VarApi<T2> : VarApi12, VarApi23 {
  void funcA2();
};

template<>
struct VarApi<T2> : VarApi23 {
  void funcA3();
};
struct varapicomon{
无效公共();
};
结构VarApi12:虚拟varapicomon{
void funcA1_2();
};
结构VarApi23:虚拟varapicomon{
void funcA2_3();
};
模板
结构VarApi;//未定义
模板
结构VarApi:VarApi12{
void funcA1();
};
模板
结构VarApi:VarApi12,VarApi23{
void funcA2();
};
模板
结构VarApi:VarApi23{
void funcA3();
};
这在很大程度上取决于成员

这可以工作并实现上述功能。问题在于,用户仍然可以通过以下方式覆盖此选项:

VarApi<T2> v2;
v2.funcA1<T1>(); // NOT ERROR
VarApi<T2> v2;
v2.funcA1<T1>(); // NOT ERROR

这可以防止模板“劫持”。

我的建议是基于您能够提供实现,但希望隐藏它

有一个基本的实现,它实现了一切

template <class X> class Base
{
public:
    void A();
    void B();
    void C();
    void D();
    void E();
};
模板类基类
{
公众:
使A()无效;
无效B();
无效C();
无效D();
无效E();
};
拥有一个派生类,该派生类继承受保护的,但随后从基中发布所有公共方法

template <class X> class Mid: protected Base<X>
{
public:
    using Base::A;
    using Base::B;
    using Base::C;
    // D & E are contentious
};
模板类Mid:受保护的基础
{
公众:
使用Base::A;
使用Base::B;
使用Base::C;
//D&E是有争议的
};
具有实际发布的类别,其中每个变体T1、T2、T3都是专门的。
这些类都是从第二个类公开继承的,但是publicfriend会发布它们确实支持的方法

template <class X> class Top: public Mid<X> {};
template <> class Top<X1>: public Mid<X1>
{
public:
    using Base::D;
    // Can't get E
};
template <> class Top<X2>: public Mid<X2>
{
public:
    // Can't get D
    using Base::E;
};
模板类Top:public Mid{};
模板类Top:公共Mid
{
公众:
使用Base::D;
//得不到E
};
模板类Top:公共Mid
{
公众:
//不可能
使用Base::E;
};
增益:无法访问要隐藏的方法。没有模板函数魔术


损失:发布的规则是任意的,根本不是由“可读”的结局驱动的。您也不能轻易地使用继承来构建规则,尽管您可能可以使用LikeX第二个模板参数。

>“>但是我的结构是虚拟的。”不,这里没有虚拟的。@FantasticMrFox如果您的结构是虚拟的,请编辑问题以反映问题的实际复杂性。否则,我们就试着解决你告诉我们的问题。示例必须是最少的,但必须是完整的。@Jean-MichaëlCelerier如果我想共享公共功能,就会有,除非我在每个专门化中都重新实现了所有功能…@FantasticMrFox不太可能。您可以使用友元函数或基类。将公共功能放在
func\u提供程序\u base
中,并使
foo
或所有
func\u提供程序
从中继承,这样就不会有任何虚拟。完美。这么简单。
template <class X> class Base
{
public:
    void A();
    void B();
    void C();
    void D();
    void E();
};
template <class X> class Mid: protected Base<X>
{
public:
    using Base::A;
    using Base::B;
    using Base::C;
    // D & E are contentious
};
template <class X> class Top: public Mid<X> {};
template <> class Top<X1>: public Mid<X1>
{
public:
    using Base::D;
    // Can't get E
};
template <> class Top<X2>: public Mid<X2>
{
public:
    // Can't get D
    using Base::E;
};