如何根据特定类型任意启用或禁用类方法



我有这样的类:

struct X
{
    enum Type { INT, FLOAT };
    using val_t = std::tuple<int, float>;
    X(Type t) : type(t) {}
    Type type;
    template<typename T>
    X& operator =(T x)
    {
        // ???
        static_assert(T is the same as `type');
        // ???
        std::get<type>(val) = x;
        return *this;
    }
    val_t val;
};

如果用户尝试分配不兼容的值,是否可以在编译时断言?

例如:

X x1(X::INT);
x1 = 5; // OK
x1 = 3.14; // compilation error

注意:我更喜欢将类保留为不是模板,因为我需要将其实例保存在集合中(如std::vector等(。

你不能:type_的值是运行时数据,编译错误不是在运行时确定的。

你可以做:

enum Type { INT, FLOAT };
template<Type type_>
struct X {
  using val_t = std::tuple<int, float>;

  template<typename T>
  X& operator =(T x) {
    // ???
    static_assert((type_==INT&&std::is_same<T,int>{})||(type_==FLOAT&&std::is_same<T,float>{}),
      "types do not match"
    );
    std::get<T>(val) = x;
    return *this;
  }
  val_t val;
};
X<INT> x1;
x1 = 5; // OK
x1 = 3.14; // compilation error

但我看不出多大意义。

一种方法是拥有一个不执行检查的基类型,只存储状态,以及一个知道其类型的派生类型。

struct Base{
  enum {INT,FLOAT} Type;
  // etc
};
template<Base::Type type>
struct Derived:private Base{
  Derived():Base(type){}
  using Base::some_method; // expose base methods
  Base& get_base()&{return *this;}
  Base get_base()&&{return std::move(*this);}
  Base const& get_base()const&{return *this;}
  template<class T>
  Derived& operator=( T o){
    static_assert((type_==INT&&std::is_same<T,int>{})||(type_==FLOAT&&std::is_same<T,float>{}),
      "types do not match"
    );
    Base::operator=(std::move(o));
    return *this;
  }
};

Base 不检查,充其量是运行时断言。 Derived在编译时进行检查。

当你在编译时静态知道类型时,你使用Derived<INT> d;;当你不知道或需要忘记时,使用.get_base()Base b(type_enum_val);

考虑到你有Type type;你不能在编译时断言type是 INT 还是 FLOAT 或任何你拥有的东西。对于该检查,您只能在运行时断言。

对于其他所有内容,您可以进行编译时检查,并使用一些模板元编程进行运行时检查:

namespace detail_tuple
{
    template <typename T, std::size_t N, typename... ARGS>
    struct get_by_type_impl {
        enum {
            kIdx = N
        };
    };
    template <typename T, std::size_t N, typename... ARGS>
    struct get_by_type_impl<T, N, T, ARGS...> {
        enum {
            kIdx = N
        };
    };
    template <typename T, std::size_t N, typename U, typename... ARGS>
    struct get_by_type_impl<T, N, U, ARGS...> {
        enum {
            kIdx = get_by_type_impl<T, N + 1, ARGS...>::kIdx
        };
    };
}
template <typename, typename>
struct validator;
template <typename T, typename... ARGS>
struct validator < T, std::tuple<ARGS...> >
{
    static void validate(const std::size_t type_idx)
    {
        //compiletime checks
        //get index of type T in ARGS...
        constexpr auto ind = detail_tuple::get_by_type_impl<T, 0, ARGS...>::kIdx;
        //check if index is valid
        static_assert(ind < sizeof...(ARGS), "Type index out of bounds, type T is was not found in the tuple!");
        //runtime checks
        if (type_idx != ind)
            std::cout << "Incompatible type index!n";
    }
};
struct X
{
    enum Type
    {
        INT = 0,
        FLOAT,
        TYPE_COUNT,
    };
    using val_t = std::tuple<int, float>;

    X(Type t) : type(t) {}
    Type type;
    template<typename T>
    X& operator =(const T& x)
    {
        validator<T, val_t>::validate(type);
        std::get<T>(val) = x;
        return *this;
    }
    val_t val;
};

对于该std::get使用类型 T 而不是 type

相关内容

  • 没有找到相关文章

最新更新