C++ 带模板包的SFINAE:如果没有模板参数,则禁用成员

C++ 带模板包的SFINAE:如果没有模板参数,则禁用成员,c++,templates,enums,sfinae,C++,Templates,Enums,Sfinae,我想定义一个带有可选模板参数的类,以便: 如果参数存在并且是枚举类,则定义 运算符() 可以在不使用其他模板的情况下对类进行IStation 参数(在这种情况下,运算符()不存在) 目标是允许通过可选的枚举类访问数组元素 代码: 关于运算符()的定义。这是因为当使用单个参数表示数据时,未定义enum\u wrapper::type。 但是,在operator()的定义中,模板参数bool activate及其返回类型std::enable\u(如果时实例化operator())。。。T为空。

我想定义一个带有可选模板参数的类,以便:

  • 如果参数存在并且是枚举类,则定义 运算符()
  • 可以在不使用其他模板的情况下对类进行IStation 参数(在这种情况下,运算符()不存在)
目标是允许通过可选的枚举类访问数组元素

代码:

关于运算符()的定义。这是因为当使用单个参数表示数据时,未定义
enum\u wrapper::type
。 但是,在
operator()
的定义中,模板参数
bool activate
及其返回类型
std::enable\u(如果
是为了防止参数pack
typename>时实例化
operator()
)。。。T
为空。 为什么在SFINAE下不简单地放弃
操作符()
的定义

另外,当
enum_wrapper::type
不是
enum类时,我想使用
std::is_enum
进一步消除运算符()。 在什么情况下

std::enable_if<std::is_enum_v<(enum_wrapper<T...>::type)>>
std::启用

是否应该插入以使SFINAE工作

问题在于
operator()
的参数类型不依赖于模板参数(to
operator()

您可以通过指定新参数包(必须与类相同)的间接寻址使其依赖(不幸的是,我们不能默认参数包,否则我们会)

然后我们可以这样称呼它:

data<3> a; // no operator()

data<3, int> b; // operator() viable
b.x[0] = 1;
b.x[1] = 3;
b.x[2] = 5;
std::cout << b(1) << std::endl; // print '3'
您可以像以前一样调用它,但仍然没有为
a
定义
操作符()。但是,如果尝试调用
b(2.0)
,则会触发静态断言


我想说——与其在
operator()
@SamVarshavchik中使用
std::enable\u if
和制作
operator()
模板,不如在
operator()
中粘贴
static\u assert
——定义“cleaner”。如果OP必须管理重载,SFINAE是唯一的方法。静态断言将导致错误,而不是优雅地忽略错误重载。这里没有提到重载
()
。只有一个工作的
()
操作符,这就是我解析它的方式。不使用参数包应该更简单,而是使用单个模板参数,
typename E=void
,然后使用调用
std::is_enum\u v
@SamVarshavchik的
static\u assert
——我的分析是,应该优雅地删除生成的重载。如果你怀疑OP的目标走错了方向,请澄清目标。不要设定一个目标,对“未来化”做出笼统的陈述。你很容易被证明是错的。@Sam Varshavchik谢谢你的评论。我确实更愿意在无效时通过SFINAE放弃
operator()
的定义;正如@StoryTeller所注意到的,这将允许更大的灵活性,例如在重载
operator()
时。在
enum_wrapper
中使用默认模板参数是一个可行的选项,本质上相当于@andyg在下面发布的解决方案感谢您的解决方案。我相信您对
enum\u wrapper
的定义相当于将
typename T0=int
设置为默认参数,对吗?我认为,定义< >代码>枚举包装器< /> >“代码> >枚举包装器< /> >没有<代码>类型字段,但不幸的是,SfayAe将不能工作,至少是用当前C++。”弗朗西斯科:是的。同意使用空枚举包装器。enum_包装器的空包缺乏专门化,这就是SFINAE中的问题所在。另一种选择是专门化整个类@francesco:参见我的更新帖子。当我们将fn的参数设置为模板参数时,我们可以实现适当的SFINAE,但随后我们会将检查推迟到函数中的
static\u assert
。非常感谢!有趣地使用
static\u assert
来克服SFINAE的(当前)限制。
std::enable_if<std::is_enum_v<(enum_wrapper<T...>::type)>>
template <bool activate = (sizeof...(T) > 0), typename... U>
std::enable_if_t<activate && std::conjunction_v<std::is_same<T, U>...>, int>&
operator()(const typename enum_wrapper<U...>::type& e)
{ return x[static_cast<std::size_t>(e)]; }
template<class...>
struct enum_wrapper{using type = int;};

template <typename T0, typename... T1>
struct enum_wrapper<T0, T1...> {
   typedef T0 type;
};

//...

template <bool activate = (sizeof...(T) > 0)>
std::enable_if_t<activate, int>&
operator()(const typename enum_wrapper<T...>::type& e)
{ return x[static_cast<std::size_t>(e)]; }
data<3> a; // no operator()

data<3, int> b; // operator() viable
b.x[0] = 1;
b.x[1] = 3;
b.x[2] = 5;
std::cout << b(1) << std::endl; // print '3'
template <class U, bool activate = (sizeof...(T) > 0)>
std::enable_if_t<activate, int>&
operator()(const U& e)
{
   static_assert(std::is_same_v<U, typename enum_wrapper<T...>::type>, L"argument type to operator() is incorrect");
   return x[static_cast<std::size_t>(e)]; 
}