我有一个这样的课程:
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
等)。
答案 0 :(得分:0)
考虑到你有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
答案 1 :(得分:0)
你不能: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
在编译时进行检查。
Niw当您在编译时静态地知道类型时使用Derived<INT> d;
;如果您不这样做或需要忘记,请使用.get_base()
或Base b(type_enum_val);
。