【发布时间】:2013-10-03 05:29:22
【问题描述】:
我正在尝试使用 C++11,而不是将 C++ 用作 C++98(我来自 C),并且我现在已经达到了类型特征,而不是跳入我认为的标准' d 尝试解决问题。
通常我会使用继承来添加基于类型的方法,并依赖于用户,但我想使用特征,现在我不希望最终用户使用我的“自定义”,这是因为这是一个实验。
我首先创建了一个 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) 和int count(T&),这将使用 == 来比较 Ts。这就是我将其留给用户的意思,他们可以根据/他们/对类型的了解来选择他们想要的列表。
我想使用EnableIf(当我更有信心时使用std::enable_if)来代替,这样当模板被删除时,功能只有enabled,如果该类型能够被使用方式。
列表定义
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 和 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 从来没有真正存在过,而且设计有点像 virtual 的反面,没有什么说你不能使用实例来调用静态方法,我刚刚检查了 C++03 标准,部分9.4确认了,这个有变化吗?
SFINAE
当hasMember 尚未定义时,是否可以使用SFINAE 来假设False?我知道这不适用于基本类型等,这是一个实验。在我有信心之前,我不会在生产中使用这些技术。
【问题讨论】:
标签: c++ c++11 metaprogramming