为某些模板参数设置public/private on template函数

set public/private on template function for some certain template parameter

本文关键字:private on template 函数 public 设置 参数      更新时间:2023-10-16

是否可以使某个模板函数对某些模板参数具有2个可访问级别?(通过拆分为2个函数?)

class B{
    enum ENU{
        T0,T1,T2   
    }
    template<ENU T=T0> someType f(){  ... } //want T1,T2 = public,  T0 = private
};

当前使用情况(解决方案不应更改):-

B b;
int aa=b.f<T0>(); //should fail
std::string bb=b.f<T1>();// should ok

编辑: B有很多这样的函数



这里是完整的代码(以防有人想编辑或使用)https://ideone.com/ryNCml.

我怀疑你想做的是可能的,因为在c++中不允许对值进行专门化函数。

如果您不需要枚举,您可以编写类似的内容:

class B {
public:
     struct T0{};
     struct T1{};
     struct T2{};
     template<typename T> void f(T, ...) {
          static_assert(std::is_same_v<T, T1> || std::is_same_v<T, T2>); 
     }
private:
     void f(T0, ...) {}
};
int main(int argc, char **argv) {
    B b{};
    b.f(T1{}); // Should compile
    b.f(T0{}); // Should not compile
}

如果您想使用相同的函数实现,您可以将其转发给公共方法,或者简单地将T0设置为私有。

或者,您可以使用可以转换值的代理对象,尽管我不确定这是标准的c++还是我熟悉的编译器的扩展:

class B {
public:
    enum class T { //< Strong typed!
        T0,
        T1,
        T2
    }
    template <T t>
    struct TWrapper {};
    template <T ActualT>
    void f(..., TWrapper<ActualT> tw = TWrapper<ActualT>{}); 
private:
    template <>
    struct TWrapper<T0> {};
}

据我所知,您希望在调用成员方法f时禁止使用T0作为模板参数。
为此,您可以使用std::enable_ifstatic_assert
它遵循一个最小的工作示例:

#include<type_traits>
class B {
public:
    enum ENU { T0,T1,T2 };
    template<ENU T>
    std::enable_if_t<(T==T1||T==T2),int>
    f() { return 42; }
    template<ENU T>
    int g(){
        static_assert(T==T1||T==T2, "not allowed");
        return 42;
    }
};
int main() {
    B b;
    b.f<B::T1>();
    // It doesn't work
    //b.f<B::T0>();
    b.g<B::T1>();
    // It doesn't work
    //b.g<B::T0>();
}

如果您只想支持有限的模板参数集,我会编写三个不是模板函数的函数,并给它们适当的可见性。然后将它们委托给一个私有模板函数来完成这项工作。这看起来像:

class B{
public:
    enum ENU{
        T0,T1,T2   
    }
private:
    template<ENU T=T0> int f(){ 
          std::cout<<"In enum "<<T<<std::endl;
          return 0;
    }
protected:
    someType fT0() { return f<T0>(); }
public:
    someType fT1() { return f<T1>(); }
    someType fT2() { return f<T2>(); }
};

与您的要求相反,用法发生了变化——但这通常是最简单的方法:

B b;
int aa=b.fT0(); // fails
int bb=b.fT1();// ok

或者,你可以让模板是公共的,但是给它一个虚拟实参(默认值),并让虚拟实参的类型依赖于模板形参(通过traits)。如果dummy的类型是私有类,则该模板只能由成员调用。

template <ENU T>
struct protection_traits;
class B{
friend class protection_traits<T0>; // So it has access to Protected.
protected:
    struct Protected{};
public:
    struct Public{};
    enum ENU{
        T0,T1,T2   
    }
    template<ENU T=T0> int f( typename protection_traits<T>::type = {})
      { std::cout<<"In enum "<<T<<std::endl; }
};
template <ENU T>
struct protection_traits 
{
    typedef B::Public type;   // Default to public
};
template<>
struct protection_traits<T0> 
{ 
    typedef B::Protected type;  // But T0 uses Protected
};

用法:

B b;
int aa=b.f<T0>(); // fails (no access to B::Protected)
int bb=b.f<T1>(); // ok

注意:后一种解决方案还没有提供给编译器。会有错别字