C++ 如何根据特定类型任意启用或禁用类方法?
我有一门课是这样的:C++ 如何根据特定类型任意启用或禁用类方法?,c++,templates,sfinae,enable-if,C++,Templates,Sfinae,Enable If,我有一门课是这样的: struct X { 枚举类型{INT,FLOAT}; 使用val_t=std::tuple; X(t型):类型(t){} 类型; 模板 X&运算符=(tx) { // ??? 静态断言(T与'type'相同); // ??? std::get(val)=x; 归还*这个; } val_t val; }; 如果用户试图分配不兼容的值,是否可以在编译时断言 例如: xx1(X::INT); x1=5;//好啊 x1=3.14;//编译错误 注意:我更喜欢将类保留为模板,因
struct X
{
枚举类型{INT,FLOAT};
使用val_t=std::tuple;
X(t型):类型(t){}
类型;
模板
X&运算符=(tx)
{
// ???
静态断言(T与'type'相同);
// ???
std::get(val)=x;
归还*这个;
}
val_t val;
};
如果用户试图分配不兼容的值,是否可以在编译时断言
例如:
xx1(X::INT);
x1=5;//好啊
x1=3.14;//编译错误
注意:我更喜欢将类保留为模板,因为我需要将其实例保留在集合中(如
std::vector
等)。考虑到您有类型如果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;
};
名称空间详细信息\u元组
{
模板
结构按类型获取{
枚举{
kIdx=N
};
};
模板
结构按类型获取{
枚举{
kIdx=N
};
};
模板
结构按类型获取{
枚举{
kIdx=通过类型获取类型:kIdx
};
};
}
模板
结构验证器;
模板
结构验证器
{
静态无效验证(const std::size\u t type\u idx)
{
//编译时间检查
//获取参数中T类型的索引。。。
constexpr auto ind=detail\u tuple::get\u by\u type\u impl::kIdx;
//检查索引是否有效
静态_断言(ind std::cout不能:类型的值是运行时数据,编译错误不会在运行时确定
你可以做:
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
enum类型{INT,FLOAT};
模板
结构X{
使用val_t=std::tuple;
模板
X&运算符=(tx){
// ???
静态断言((type_==INT&&std::is_same{})| |(type_==FLOAT&&std::is_same{}),
“类型不匹配”
);
std::get(val)=x;
归还*这个;
}
val_t val;
};
x1;
x1=5;//正常
x1=3.14;//编译错误
但我看不出有什么意义
一种方法是让不进行检查的基类型只存储状态,而让派生类型知道其类型
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;
}
};
struct Base{
枚举{INT,FLOAT}类型;
//等
};
模板
派生结构:私有基{
派生():基(类型){}
使用Base::some_method;//公开基本方法
Base&get_Base()&{return*this;}
Base get_Base()&&{return std::move(*this);}
Base const&get_Base()const&{return*this;}
模板
派生运算符=(TO){
静态断言((type_==INT&&std::is_same{})| |(type_==FLOAT&&std::is_same{}),
“类型不匹配”
);
Base::operator=(std::move(o));
归还*这个;
}
};
Base
不检查,充其量它在运行时断言。Derived
在编译时检查
Niw当您在编译时静态地知道类型时,您可以使用派生d;
;当您不知道或需要忘记时,可以使用.get_base()
或abase b(type_enum\u val)
如果你模板化类而不是方法,是的,可能会有编译时错误。std::is__same
要检查T是否为float/int/whatever@Jarod42,我编辑了我的问题,提到我希望将其作为模板保留,因为类的实例保存在std::vector
X x1(rand()?X::INT:X::FLOAT)
x1=5.2;
-确定还是错误?@Raxvan,您能提供一个代码示例吗?谢谢。请注意,这将禁用SFINAE检查。如果您有一个泛型类型,并且您想查看foo=bar
是否工作,那么您现在会出现一个硬错误,而不是一个“无”答案。很抱歉,但这不起作用。static\u assert
应该针对用于构造X的特定类型进行ck。我提供了一个示例,其中分配给不同类型会导致编译错误。在您的示例中,我可以分配int
和float
值,而不会产生编译错误。我相信有机会实现它,因为在编译时可以知道X的类型。我尝试使用<代码> CONTXPROP<代码>,但找不到任何工作解决方案。@ AlxelBulkman:X的类型是X。C++是如何运行的。如果<代码> CONTXPROP>代码>将工作,那么代码>模板<代码>将工作。在幕后,它们是紧密相关的。问题是你不能做出选择。X
,或者只有一个X
类型。@alex有这样一个“机会”,但它涉及的是模板非类型参数,而不是构造函数参数。如果不使用具有自动定理检查和将所述证明传递给参数调用功能的类似coq的前置条件后置条件系统,则不会在运行时对您告知编译器的数据进行编译时断言。不会发生变化的数据对于C++中变量的实例,在运行时“变化”是用它的类型来编码的。我们可以有一个表达式,它不能基于“运行时”(好,在编译时运行)状态,但这不是你问的。我是说在C++ 17中,我可以把Cor参数的类型转换成实例中的类型数据,但这只是语法糖。Yakk,我明白你的观点。同意,在C++的这个阶段似乎是不可能的。我希望他们给语言添加一些基本的反射。