gpt4 book ai didi

c++ - SFINAE成员(member)通过

转载 作者:太空狗 更新时间:2023-10-29 20:43:58 25 4
gpt4 key购买 nike

我想知道是否有可能创建一个类来充当 std::enable_if 和 SFINAE 成员检测器之间的组合。

class foo
{
public:
int bar;
};

template <class T>
typename enable_if_has_bar<T>::type ReturnBar (const T& value)
{
return value.bar;
}

所以我尝试这样做。

class foo
{
public:
int bar;
};

template <class C, C>
class Check;

template <class T, class Enable = void>
class enable_if_has_bar
{};

template <class T>
class enable_if_has_bar<T, Check <decltype(&T::bar),&T::bar>>
{
public:
typedef decltype(static_cast<T*>(0)->*static_cast<decltype(&T::bar)>(0)) type;
};

template <class T>
typename enable_if_has_bar<T>::type ReturnBar (const T& value)
{
return value.bar;
}

int main ()
{
foo foobar;
foobar.bar = 42;

cout << ReturnBar(foobar) << endl;
}

( http://ideone.com/WKTfmQ )

这似乎行不通,而且我对 SFINAE 的精通技术还不够精通。也许有人可以改进/修复它?因为我不知所措。

最佳答案

我通常更喜欢创建自定义 enable_if -style 类型,因为我发现使用单个特征类型而不是 enable_if<some_trait<T>, another_trait<T>> 的组合更容易阅读代码.但在这种情况下,您的代码中存在一些问题,导致它无法正常工作。

你的 enable_if_has_bar specialization 永远不会被选中,ReturnBar 的返回类型只是实例化主模板,enable_if_has_bar<foo, void> , 并且永远不会定义嵌套的 type .没有什么会导致特化被实例化,所以没有什么可以检查 T::bar 是否存在。是一个有效的表达式。

你的 decltype(static_cast<T*>(0)->*static_cast<decltype(&T::bar)>(0))表达式将导致 int&不是int正如你可能想要的那样。这是因为 decltype(foobar.*(&foo::bar))相当于decltype(foobar.bar)foobar.bar是左值,所以 decltypeint& .函数 ReturnBar如果它返回 int& 将无法编译因为参数 value是常量,所以你不能绑定(bind) value.bar到非常量 int& .

这是一个工作版本:

template <class T>
class has_bar
{
template<typename U, typename = decltype(&U::bar)>
static std::true_type
test(U*);

static std::false_type
test(...);

public:
static const int value = decltype(test((T*)nullptr))::value;
};

template<typename T, bool = has_bar<T>::value>
struct enable_if_has_bar
{ };

template<typename T>
struct enable_if_has_bar<T, true>
: std::decay<decltype(std::declval<T&>().*(&T::bar))>
{ };

这首先声明了助手 has_bar回答类型是否具有嵌套成员的问题。该助手使用 SFINAE 获得 truefalse值(value)。如果&T::bar是一个有效的表达式然后 test 的第一个重载将被使用,返回 true_type所以 value将设置为 true_type::valuetrue .否则将选择回退过载并且value设置为 false .

然后 enable_if_has_bar模板使用默认模板参数,该参数被推断为 has_bar<T>::value 的值. has_bar<T>::value 时使用主模板是假的。 has_bar<T>::value 时使用特化是真的,在这种情况下我们知道表达式 &T::bar是有效的,可以在 decltype 表达式中使用它来获取类型。

std::decay用于打开 int& decltype 表达式的结果为 int .继承自 decay比使用它来定义成员要短一些,后者是:

typedef typename std::decay<decltype(std::declval<T&>().*(&T::bar))>::type type;

我使用了标准实用程序 declval<T>()在未评估的表达式中,与 static_cast<T*>(0) 相比,它的类型更短,更符合习惯和表达方式。 .

使用 decay 的替代方法将是另一种帮助类型来获取类型 int来自类型 int T::*例如

template<typename T>
struct remove_class;
{ };

template<typename Member, typename Class>
struct remove_class<Member Class::*>
{
typedef Member type;
};

template<typename T>
struct enable_if_has_bar<T, true>
: remove_class<decltype(&T::bar)>
{ };

(名称 remove_class 不是很好,但基本上它采用指向数据成员的指针类型并给出成员的类型。)

关于c++ - SFINAE成员(member)通过,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14095872/

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