gpt4 book ai didi

c++ - 类型特征实验,SFINAE 似乎不起作用,提示缺少错误形式的某些东西

转载 作者:行者123 更新时间:2023-11-30 01:20:38 24 4
gpt4 key购买 nike

我正在尝试使用 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;
};

我现在预计只有 EnableIftrue有一个名为“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 当我更有信心时)改为这样做,这样当模板被冲压时功能只有 enable d 如果类型能够以这种方式使用。

列表定义
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 从来没有真正存在过,而且设计有点像虚拟的对立面,没有什么说你不能使用实例来调用静态方法,我刚刚检查了 C++03 标准,第 9.4 节证实了这一点,这有变化吗?

SFINAE

是否可以使用 SFINAE 来假设 FalsehasMember还没有定义?我知道这不适用于基本类型等,这是一个实验。在我有信心之前,我不会在生产中使用这些技术。

最佳答案

问题在这里:

virtual
typename EnableIf<T::hasEquality::value, int>::type
count(const T& what) const =0;

您遇到了另一个示例,其中泛型编程(模板)和面向对象的编程风格发生冲突。

SFINAE 是一种使用模板的元编程技术。尽管出现(使用 T ),上面声明的函数不是模板。它是模板类中的一个普通函数。模板类型参数 TList 的参数和 不是 count .

例如,以下是 SFINAE 的示例:
template<class T>
class List {
public:
template<class T>
class List {
public:
// ...
template <typename U>
typename EnableIf<std::is_same<U, T>::value && U::hasEquality::value, int>::type
count(const U& what) const { std::cout << "1\n"; }

template <typename U>
typename EnableIf<std::is_same<U, T>::value && !U::hasEquality::value, int>::type
count(const U& what) const { std::cout << "2\n"; }
};

};

int main() {
A a(1);
B b;
List<A> la;
la.count(a); // outputs 1
List<B> lb;
lb.count(b); // ouputs 2
}

注意这两个 count s 现在是模板(参数化于 U )。两者仅在 T 时才有效与 U 的类型相同.这是接受 T 的解决方法只有(它并不完美,例如,它丢弃了隐式转换)。此外,第一个要求 U::hasEquality::value == true第二个要求相反。

这里的关键点是 SFINAE 适用于模板。

但正如你所看到的,我改变了你的设计并制作了 count非虚拟。不幸的是,您无法制作 count函数高于虚拟,因为模板函数不能是虚拟的。

基本问题如下。模板函数只有在被调用时才会被实例化。所以当编译器解析 List (我的版本)它还不知道 count 的所有实例化那将会存在。

对于每个虚函数,虚表中都应该有一个条目,当编译器解析 List 时它必须知道虚拟表中有多少条目。

因此,一方面,在解析 List 时编译器不知道模板实例的数量,另一方面,它必须知道虚函数的数量。结论是模板函数不能是虚拟的。

关于c++ - 类型特征实验,SFINAE 似乎不起作用,提示缺少错误形式的某些东西,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19151466/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com