ASt*_*oob 8 c++ templates enable-if c++11
我正在创建一个非常小的C++项目,我想根据自己的需要创建一个简单的矢量类.该std::vector模板类不会做.当向量类由chars(即vector<char>)组成时,我希望它能够与a进行比较std::string.经过一番乱搞之后,我编写的代码既可以编译也可以执行我想要的操作.见下文:
#include <string>
#include <stdlib.h>
#include <string.h>
template <typename ElementType>
class WorkingSimpleVector {
public:
const ElementType * elements_;
size_t count_;
// ...
template <typename ET = ElementType>
inline typename std::enable_if<std::is_same<ET, char>::value && std::is_same<ElementType, char>::value, bool>::type
operator==(const std::string & other) const {
if (count_ == other.length())
{
return memcmp(elements_, other.c_str(), other.length()) == 0;
}
return false;
}
};
template <typename ElementType>
class NotWorkingSimpleVector {
public:
const ElementType * elements_;
size_t count_;
// ...
inline typename std::enable_if<std::is_same<ElementType, char>::value, bool>::type
operator==(const std::string & other) const {
if (count_ == other.length())
{
return memcmp(elements_, other.c_str(), other.length()) == 0;
}
return false;
}
};
int main(int argc, char ** argv) {
// All of the following declarations are legal.
WorkingSimpleVector<char> wsv;
NotWorkingSimpleVector<char> nwsv;
WorkingSimpleVector<int> wsv2;
std::string s("abc");
// But this one fails: error: no type named ‘type’ in ‘struct std::enable_if<false, bool>’
NotWorkingSimpleVector<int> nwsv2;
(wsv == s); // LEGAL (wanted behaviour)
(nwsv == s); // LEGAL (wanted behaviour)
// (wsv2 == s); // ILLEGAL (wanted behaviour)
// (nwsv2 == s); // ??? (unwanted behaviour)
}
Run Code Online (Sandbox Code Playgroud)
我相信我理解为什么会发生错误:编译器为其创建类定义NotWorkingSimpleVector<int>,然后我的operator==函数的返回类型变为:
std::enable_if<std::is_same<int, char>::value, bool>::type
Run Code Online (Sandbox Code Playgroud)
然后变成:
std::enable_if<false, bool>::type
Run Code Online (Sandbox Code Playgroud)
然后产生错误:没有type成员std::enable_if<false, bool>,这确实是enable_if模板的整个点.
我有两个问题.
operator==for 的定义NotWorkingSimpleVector<int>,就像我想要的那样?这有兼容性的原因吗?是否还有其他用例我不知道; 对这种行为存在合理的反驳吗?WorkingSimpleVector)有效?在我看来,编译器"保留判断":由于"ET"参数尚未定义,它放弃尝试判断是否operator==存在.我们是否依赖于编译器缺乏洞察力来允许这种有条件启用的功能(即使C++规范可以接受这种"缺乏洞察力")?谢谢.
这个答案与Yakk的答案相似,但并没有那么有用(Yakk的支持任意if-expressions).然而,它更简单,更容易理解.
#include <string>
#include <stdlib.h>
#include <string.h>
template <typename ElementType>
class WorkingSimpleVector {
public:
const ElementType * elements_;
size_t count_;
// ...
template <typename ET = ElementType>
inline typename std::enable_if<std::is_same<ET, char>::value && std::is_same<ElementType, char>::value, bool>::type
operator==(const std::string & other) const {
if (count_ == other.length())
{
return memcmp(elements_, other.c_str(), other.length()) == 0;
}
return false;
}
};
template <typename ElementType>
class NotWorkingSimpleVector {
public:
const ElementType * elements_;
size_t count_;
// ...
inline typename std::enable_if<std::is_same<ElementType, char>::value, bool>::type
operator==(const std::string & other) const {
if (count_ == other.length())
{
return memcmp(elements_, other.c_str(), other.length()) == 0;
}
return false;
}
};
int main(int argc, char ** argv) {
// All of the following declarations are legal.
WorkingSimpleVector<char> wsv;
NotWorkingSimpleVector<char> nwsv;
WorkingSimpleVector<int> wsv2;
std::string s("abc");
// But this one fails: error: no type named ‘type’ in ‘struct std::enable_if<false, bool>’
NotWorkingSimpleVector<int> nwsv2;
(wsv == s); // LEGAL (wanted behaviour)
(nwsv == s); // LEGAL (wanted behaviour)
// (wsv2 == s); // ILLEGAL (wanted behaviour)
// (nwsv2 == s); // ??? (unwanted behaviour)
}
Run Code Online (Sandbox Code Playgroud)
这通过利用我们想要的'if语句'的模板专门化来工作.我们将类作为基础std::vector,如果char值为vector<char>(第二个定义std::string),则只包含函数.否则,它根本没有功能(第一个定义NotWorkingSimpleVector<int>).该operator==参数使其成为"CRTP"(奇怪的重复模板模式).它允许模板通过使用该type函数来访问子类的字段.请记住,模板与任何其他类没有区别,因此它不能访问私有成员(除非子类将其声明为a std::enable_if<false, bool>).
他/她声明的第一件事是帮助模板,它为我们完成了这整个条件声明:
std::enable_if<std::is_same<int, char>::value, bool>::type
Run Code Online (Sandbox Code Playgroud)
变量模板是可怕的,我认为在这种情况下可以删除它们.我们将其简化为:
std::enable_if<false, bool>::type
Run Code Online (Sandbox Code Playgroud)
enable_if的operator==类型是一个空结构,如果条件NotWorkingSimpleVector<int>不是WorkingSimpleVector(见的第一个定义operator==).如果是,则std::vector类型是值char.我们的定义vector<char>只是std::string在NotWorkingSimpleVector<int>每次使用这个结构时都不需要我们写.
接下来,我们定义一个实现我们想要的行为的模板
#include <string>
#include <stdlib.h>
#include <string.h>
template <typename ElementType>
class WorkingSimpleVector {
public:
const ElementType * elements_;
size_t count_;
// ...
template <typename ET = ElementType>
inline typename std::enable_if<std::is_same<ET, char>::value && std::is_same<ElementType, char>::value, bool>::type
operator==(const std::string & other) const {
if (count_ == other.length())
{
return memcmp(elements_, other.c_str(), other.length()) == 0;
}
return false;
}
};
template <typename ElementType>
class NotWorkingSimpleVector {
public:
const ElementType * elements_;
size_t count_;
// ...
inline typename std::enable_if<std::is_same<ElementType, char>::value, bool>::type
operator==(const std::string & other) const {
if (count_ == other.length())
{
return memcmp(elements_, other.c_str(), other.length()) == 0;
}
return false;
}
};
int main(int argc, char ** argv) {
// All of the following declarations are legal.
WorkingSimpleVector<char> wsv;
NotWorkingSimpleVector<char> nwsv;
WorkingSimpleVector<int> wsv2;
std::string s("abc");
// But this one fails: error: no type named ‘type’ in ‘struct std::enable_if<false, bool>’
NotWorkingSimpleVector<int> nwsv2;
(wsv == s); // LEGAL (wanted behaviour)
(nwsv == s); // LEGAL (wanted behaviour)
// (wsv2 == s); // ILLEGAL (wanted behaviour)
// (nwsv2 == s); // ??? (unwanted behaviour)
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,operator==参数是给我们"CRTP"(奇怪的重复模板模式).有关其重要性的详细信息,请参阅上面的"简单答案".
接下来,type如果条件满足,我们声明只具有此函数的类型:
std::enable_if<std::is_same<int, char>::value, bool>::type
Run Code Online (Sandbox Code Playgroud)
所以,std::enable_if<false, bool>类型是:
enable_ifoperator== 什么时候 NotWorkingSimpleVector<int>最后,在完成所有这些之后,我们可以使用以下内容创建我们想要的类:
std::enable_if<false, bool>::type
Run Code Online (Sandbox Code Playgroud)
哪个按要求工作.
SFINAE 在模板函数中工作。在模板类型替换的上下文中,替换的直接上下文中的替换失败不是错误,而是算作替换失败。
但请注意,必须有有效的替换,否则您的程序格式不正确,无需诊断。我认为存在这种情况是为了将来可以向语言中添加进一步的“更具侵入性”或完整的检查,以检查模板函数的有效性。只要所述检查实际上检查模板是否可以用某种类型实例化,它就成为有效检查,但它可能会破坏期望没有有效替换的模板有效的代码(如果这是有意义的)。如果没有可以传递给让程序operator==编译的函数的模板类型,这可能会使您的原始解决方案成为格式错误的程序。
在第二种情况下,没有替换上下文,因此 SFINAE 不适用。失败是无可替代的。
最后我查看了传入的概念提案,您可以向模板对象中依赖于该对象的模板参数的方法添加 require 子句,并且在失败时,该方法将不会被考虑进行重载解析。这实际上就是您想要的。
在当前标准下,没有符合标准的方法可以做到这一点。第一次尝试是人们通常会做的尝试,它确实可以编译,但在技术上违反了标准(但不需要对故障进行诊断)。
我想出的符合标准的方法来做你想做的事:
如果条件失败,则将该方法的参数之一更改为对从未完成类型的引用。如果不调用,该方法的主体永远不会被实例化,并且该技术阻止它被调用。
使用 CRTP 基类帮助程序,该帮助程序使用 SFINAE 根据任意条件包含/排除方法。
template <class D, class ET, class=void>
struct equal_string_helper {};
template <class D, class ET>
struct equal_string_helper<D,ET,typename std::enable_if<std::is_same<ET, char>::value>::type> {
D const* self() const { return static_cast<D const*>(this); }
bool operator==(const std::string & other) const {
if (self()->count_ == other.length())
{
return memcmp(self()->elements_, other.c_str(), other.length()) == 0;
}
return false;
}
};
Run Code Online (Sandbox Code Playgroud)
我们这样做的地方:
template <typename ElementType>
class WorkingSimpleVector:equal_string_helper<WorkingSimpleVector,ElementType>
Run Code Online (Sandbox Code Playgroud)
如果我们选择,我们可以从 CRTP 实现中重构条件机制:
template<bool, template<class...>class X, class...>
struct conditional_apply_t {
struct type {};
};
template<template<class...>class X, class...Ts>
struct conditional_apply_t<true, X, Ts...> {
using type = X<Ts...>;
};
template<bool test, template<class...>class X, class...Ts>
using conditional_apply=typename conditional_apply_t<test, X, Ts...>::type;
Run Code Online (Sandbox Code Playgroud)
然后我们将没有条件代码的 CRTP 实现拆分出来:
template <class D>
struct equal_string_helper_t {
D const* self() const { return static_cast<D const*>(this); }
bool operator==(const std::string & other) const {
if (self()->count_ == other.length())
{
return memcmp(self()->elements_, other.c_str(), other.length()) == 0;
}
return false;
}
};
Run Code Online (Sandbox Code Playgroud)
然后将它们连接起来:
template<class D, class ET>
using equal_string_helper=conditional_apply<std::is_same<ET,char>::value, equal_string_helper_t, D>;
Run Code Online (Sandbox Code Playgroud)
我们使用它:
template <typename ElementType>
class WorkingSimpleVector: equal_string_helper<WorkingSimpleVector<ElementType>,ElementType>
Run Code Online (Sandbox Code Playgroud)
在使用时看起来相同。但背后的机制被重构了,那么,奖金呢?
| 归档时间: |
|
| 查看次数: |
5286 次 |
| 最近记录: |