我正在尝试使用 C++11,而不是使用 C++ 作为 C++98(我来自 C)并且我已经达到了类型特征,而不是跳入我认为我会尝试的标准解决这个问题。
通常我会使用继承来添加基于类型的方法,并依赖于用户,但我想使用特征,现在我不希望最终用户使用我的“自定义”,这是因为它是一个实验.
我首先创建了一个 True 和一个 False 类型,如下所示:
struct True {
static const bool value = true;
};
struct False {
static const bool value = false;
};
然后我的enable_if
定义,我理解使用结构或类既是结构(在 C 意义上,具有大小等)又是命名空间的事实,如下所示:
template<bool B,class T>
struct EnableIf {};
template<class T>
struct EnableIf<true,T> {
typedef T type;
};
我现在希望只有EnableIf
一个true
名为“type”的“命名空间类型成员”(如果可以的话),它是模板 T 的任何内容。这似乎有效。
我知道当我尝试访问时EnableIf<false,T>::type
,由于没有type
我很确定到目前为止一切都是正确的,但我只是冗长。
我的测试用例
我选择了一个列表作为我的测试场(再次不使用标准集,因为我正在调查)通常我使用一个类层次结构来做到这一点,我有一个list
只能充当数组,唯一的额外成员将是int find(T*);
因为 T* 是 T 的身份。
然后我将它扩展为有一个int find(T&);
int find(T&,int)
andint count(T&)
这将使用 == 来比较 Ts。这就是我将其留给用户的意思,他们可以根据/他们/对类型的了解来选择他们想要的列表。
我想使用EnableIf
(稍后std::enable_if
当我更有信心时)来代替,这样当模板被删除时,功能只有enable
在类型能够以这种方式使用时才有效。
列表定义
template<class T>
class List {
public:
typedef typename T::hasEquality hasEquality;
virtual ~List() {}
virtual T& operator[](int index) =0;
virtual const T& operator[](int index) const =0;
virtual void append(T*) =0;
virtual int length() const =0;
virtual
typename EnableIf<hasEquality::value, bool>::type
operator==(const List<T>& rhs) const {
if(length() == rhs.length()) {
for(int k=0;k!=length();k++) {
if(!((*this)[k] == rhs[k])) {
return false;
}
}
return true;
} else {
return false;
}
}
virtual
typename EnableIf<T::hasEquality::value, int>::type
count(const T& what) const =0;
};
这是一个列表而不是一组,所以顺序很重要。您可以看到这应该hasEquality
具有传递性,因为:
如果 T 具有相等的概念,则 T 的列表也具有相等的概念
然后我继续实现一个单链表。
测试类型
class A {
public:
A(int value) { val = value; }
typedef True hasEquality;
bool operator==(const A& rhs) const {
if(val == rhs.val) {
return true;
}
return false;
}
private:
int val;
};
class B {
public:
typedef False hasEquality;
};
结果
int main(int,char**) {
LinkedList<A> listA;
listA.append(new A(6));
A a(6);
std::cout<<"there are "<<listA.count(a)<<" of them\n";
return 0;
}
正如你所期望的那样有效。我的第一个测试最初包括 B,但这会导致问题。
int main(int,char**) {
LinkedList<A> listA;
listA.append(new A(6));
A a(6);
std::cout<<"there are "<<listA.count(a)<<" of them\n";
LinkedList<B> listB;
return 0;
}
这没有,它失败了:
src/main.cpp: In instantiation of ‘class List<B>’:
src/main.cpp:77:7: required from ‘class LinkedList<B>’
src/main.cpp:176:16: required from here
src/main.cpp:59:2: error: no type named ‘type’ in ‘struct EnableIf<false, bool>’
operator==(const List<T>& rhs) const {
^
src/main.cpp:73:3: error: no type named ‘type’ in ‘struct EnableIf<false, int>’
count(const T& what) const =0;
^
src/main.cpp: In instantiation of ‘class LinkedList<B>’:
src/main.cpp:176:16: required from here
src/main.cpp:134:3: error: no type named ‘type’ in ‘struct EnableIf<false, int>’
count(const T& what) const {
^
make: *** [build/main.o] Error 1
出于某种原因,它将错误标记放在 typename 行之后,在我使用EnableIf
with的任何地方都不满意false
我真的不知道为什么会这样,没错,没有type
,但这是设计使然!
研究
http://en.cppreference.com/w/cpp/types/enable_if
引用:
template<bool B, class T = void>
struct enable_if {};
template<class T>
struct enable_if<true, T> { typedef T type; };
我的只是名称不同,默认的 T 是无效的,将它添加到我的(如我所料)并不能解决问题。
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/SFINAE
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/enable-if
确认我的想法。
奖金问题
constexpr 和静态
最初我尝试过struct False { constexpr bool operator==(bool what) { return !what; } };
,对于True
;
但这不起作用,我不能使用“静态”这个词来限定 operator==,但我可以使用调用constexpr static bool is(bool what);
相同效果的方法,为什么 constexpr 不暗示静态?
在我看来,constexprs 从来没有真正存在过,而且设计有点像虚拟的相反,没有什么说你不能使用实例来调用静态方法,我刚刚检查了 C++03 标准,第 9.4 节证实了这一点,这改变了吗?
SFINAE
是否可以使用 SFINAE 来假设尚未定义的False
时间?hasMember
我知道这不适用于基本类型等,这是一个实验。在我有信心之前,我不会在生产中使用这些技术。