C++ 需要帮助了解带有复杂typename参数的模板函数吗
我正在看Stroustroup的一本书“C++编程第四版”。我正试着以他为榜样来设计矩阵 他的矩阵类很大程度上依赖于模板,我尽我最大的努力找出它们。 下面是这个矩阵的一个助手类 矩阵_切片是矩阵实现中映射 元素位置的下标集。它使用了这个想法 广义切片的数量(§40.5.6):C++ 需要帮助了解带有复杂typename参数的模板函数吗,c++,metaprogramming,variadic-templates,variadic-functions,enable-if,C++,Metaprogramming,Variadic Templates,Variadic Functions,Enable If,我正在看Stroustroup的一本书“C++编程第四版”。我正试着以他为榜样来设计矩阵 他的矩阵类很大程度上依赖于模板,我尽我最大的努力找出它们。 下面是这个矩阵的一个助手类 矩阵_切片是矩阵实现中映射 元素位置的下标集。它使用了这个想法 广义切片的数量(§40.5.6): 模板 结构矩阵{ 矩阵_slice()=default;//空矩阵:无元素 矩阵切片(大小、初始值设定项列表exts);//范围 矩阵_切片(大小、初始值设定项_列表exts、初始值设定项_列表strs);//范围和步长
模板
结构矩阵{
矩阵_slice()=default;//空矩阵:无元素
矩阵切片(大小、初始值设定项列表exts);//范围
矩阵_切片(大小、初始值设定项_列表exts、初始值设定项_列表strs);//范围和步长
模板//N扩展数据块
矩阵_切片(Dims…Dims);
模板尽管缺少constepr
s,但它是一个包含两个参数的模板,但第二个参数默认为void
。为保持该约定,为其编写一个快速别名是有意义的
因此,别名应定义为:
template <bool b, class T = void>
using Enable_if = typename std::enable_if<b, T>::type;
模板
使用Enable_if=typename std::Enable_if::type;
我不知道书中是否有这个默认参数,只是这会解决这个问题
类型的赋值称为a,并按照tin上的说明执行,当您引用别名时,实际上是指它的别名。在这种情况下,这意味着当您编写Enable\u if
时,编译器会方便地将其扩展为typename std::Enable\u if::type
,为您节省所有额外的键入
最终得到的函数只有在传递给它的每个参数都可转换为std::size\t
时才可调用。这允许在不满足特定条件时忽略函数重载,这是一种比仅匹配类型以选择要调用的函数更强大的技术。的链接>std::enable_,如果
有更多关于为什么要这样做的信息,但我警告初学者,这个主题会让人兴奋。这是基本的SFINAE。例如,你可以阅读它
对于答案,我在这里使用的是std::enable_if_t
,而不是书中给出的EnableIf
,但两者是相同的:
正如@guygrer在回答中提到的,的第二个模板参数默认为void
该代码可以作为“普通”函数模板定义读取
template<typename ...Dims, typename some_unused_type = enable_if_t<true> >
size_t operator()(Dims... dims) const;
由于typename=
的rhs上没有有效的类型,因此类型推断失败。但是,由于SFINAE,它不会导致编译时错误,而是会从重载集中删除函数
实践中的结果是,该函数似乎没有被定义
其次,如果std::enable_if_t
的布尔参数为true
,则
template<typename ...Dims, typename = /* not a type */>
size_t operator()(Dims ... dims) const;
template<typename ...Dims, typename = void>
size_t operator()(Dims... dims) const;
上面的意思是,只有当All(Convertible()…
为true
时,该函数才存在。这基本上意味着函数参数都应该是整数索引(我个人认为,我会用std::is_integral
来写).这不可能是真正的代码。Enable\u if
将触发编译器错误,因为模板参数只能是编译时已知的表达式。All
的返回值不是。@SergeyA我想他只是在函数定义前面缺少了一个constepr
。我很确定这会使它工作。@GuyGreer,OP可能。但OP还缺少什么呢?;)@SergeyA He缺少模板别名Enable_If
?的默认模板参数,但这与第一条评论并不相关,所以我不确定你在暗示什么…;)@GuyGreer,我试图说明一点,当代码不起作用时,我无法解释代码是如何工作的。我不会为OP校对这个问题。但是如果可以的话,请随意回答这个问题。谢谢,但在topicA的两个挑剔问题中,它仍然没有回答另外两个问题(如果你愿意,也可以随意挑剔我的答案:P),类型推断失败可能会导致编译错误,如果可以找到另一个函数重载代替它,则不会导致编译错误。此外,Convertible
比std::is_integral
更通用,因为后者从预先确定的类型列表中检查出现的情况,而前者将接受带有c的用户定义类型onversion到std::size\t
(我很确定转换到任何整数类型就足够了,因为在那之后,类型升级就完成了,而不是转换到std::size\t
)。这是一个很好的解释。非常感谢。
template<typename... Dims,
//so here we accept the fact that we can have multiple arguments like (1,2,3,4)
typename = Enable_if<All(Convertible<Dims,size_t>()...)>>
//Evaluating and expanding from inside out my guess will be
//for example if Dims = 1,2,3,4,5
//Convertible<Dims,size_t>()... = Convertible<1,2,3,4,5,size_t>() =
//= Convertible<typeof(1),size_t>(),Convertible<typeof(2),size_t>(),Convertible<typeof(3),size_t>(),...
//= true,true,true,true,true
//All() is thus expanded to All(true,true,true,true,true)
//=true;
//Enable_if<true>
//here is point of confusion. Enable_if takes two tamplate arguments,
//Enable_if<bool B,typename T>
//but here it only takes bool
//typename = Enable_if(...) this one is also confusing
size_t operator()(Dims... dims) const; // calculate index from a set of subscripts
template<typename ...Dims,typename = Enable_if<true>>
size_t operator()(Dims... dims) const;
template <bool b, class T = void>
using Enable_if = typename std::enable_if<b, T>::type;
template<typename ...Dims, typename some_unused_type = enable_if_t<true> >
size_t operator()(Dims... dims) const;
template<typename ...Dims, typename = /* not a type */>
size_t operator()(Dims ... dims) const;
template<typename ...Dims, typename = void>
size_t operator()(Dims... dims) const;
template<typename... Dims,
typename = Enable_if<All(Convertible<Dims,size_t>()...)>>
size_t operator()(Dims... dims) const;