gpt4 book ai didi

c++ - 带有可变参数模板的 SFINAE

转载 作者:太空狗 更新时间:2023-10-29 23:50:17 24 4
gpt4 key购买 nike

我对模板编程有些陌生,所以这可能是个愚蠢的问题。我正在尝试使用可变参数模板来检查类是否有成员(称为 member)。为此,我编写了类(class)有_成员

#include <iostream>
using namespace std;

class ClassWithMember
{
public:
int member;
};
class ClassWithoutMember
{
};

template <typename T>
class has_member
{
template <typename... C>
class tester: public std::false_type
{

};
template <typename First>
class tester<First>: public std::true_type
{
void tester_fn(decltype(First::member));
};

public:
enum { value = tester<T>::value };
};

template<typename T1>
void my_function(const std::enable_if_t<has_member<T1>::value, T1> &obj)
{
cout<<"Function for classes with member"<<endl;
}

template<typename T1>
void my_function(const std::enable_if_t<!has_member<T1>::value, T1> &obj)
{
cout<<"Function for classes without member"<<endl;
}

int main()
{
ClassWithMember objWithMember;
ClassWithoutMember objWithoutMember;
my_function<ClassWithMember> (objWithMember);
my_function<ClassWithoutMember> (objWithoutMember);
}

我原以为通过 SFINAE,用没有成员的类替换专用模板会默默地失败并回退到通用模板。但是我得到了错误:

trial.cpp: In instantiation of ‘class has_member<ClassWithoutMember>::tester<ClassWithoutMember>’:
trial.cpp:28:10: required from ‘class has_member<ClassWithoutMember>’
trial.cpp:38:41: required by substitution of ‘template<class T1> void my_function(std::enable_if_t<(! has_member<T1>::value), T1>&) [with T1 = ClassWithoutMember]’
trial.cpp:49:54: required from here
trial.cpp:24:14: error: ‘member’ is not a member of ‘ClassWithoutMember’
void tester_fn(decltype(First::member));

最佳答案

SFINAE 仅适用于替换的直接上下文。除此之外的替换失败一个错误。这就是您遇到的问题:

has_member<ClassWithoutMember>::value // error

那是因为替换失败不是发生在has_membertester的声明中,而是发生在定义中。那太晚了。你需要更早地插入它。您可以使用 void_t 将其插入 has_member 的特化:

template <typename... T>
struct make_void { using type = void; };

template <typename... T>
using void_t = typename make_void<T...>::type;

template <typename T, typename = void>
struct has_member : std::false_type { };

template <typename T>
struct has_member<T, void_t<decltype(T::member)>> : std::true_type { };

现在,如果没有 T::member,当尝试选择 has_member 的正确特化时,替换失败将发生在替换的直接上下文中。替换失败不是错误,特定的特化将被丢弃,我们最终得到所需的false_type


作为旁注,您使用 enable_if_t 的方式会阻止模板推导。你应该更喜欢这样写:

template <typename T1,
std::enable_if_t<has_member<T1>::value>* = nullptr>
void my_function(const T1& obj) { ... }

template <typename T1,
std::enable_if_t<!has_member<T1>::value>* = nullptr>
void my_function(const T1& obj) { ... }

这样你就可以写:

my_function(objWithMember);
my_function(objWithoutMember);

关于c++ - 带有可变参数模板的 SFINAE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32636275/

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