SFINAE用于类型实例化
SFINAE for type instantiation
我遇到了c++中的成员检测器(Member Detector)习语,它是一种类型trait,用于判断类是否包含具有特定名称的成员。但是,如果类型不是类,则链接的示例不会像我预期的那样工作:我想要任何非类类型的false
结果。一个可能的解决方案当然是这样的,使用boost::is_class<T>
:
template<typename T>
struct general_DetectX : boost::mpl::and_<
boost::is_class<T>,
DetectX<T> >::type
{ };
bool hasX = general_DetectX<int>::value; // hasX = false
但这个问题是关于为什么原来的DetectX<T>
产生错误,而不是做SFINAE的事情。以下是链接代码相关部分的摘录(为简洁起见,删除了局部结构Fallback
和Check<U,U>
以及类型ArrayOfOne
、ArrayOfTwo
和type
):
template<typename T>
class DetectX
{
struct Derived : T, Fallback { };
template<typename U>
static ArrayOfOne & func(Check<int Fallback::*, &U::X> *);
template<typename U>
static ArrayOfTwo & func(...);
public:
enum { value = sizeof(func<Derived>(0)) == 2 };
};
可以看到DetectX::Derived
在任何重载解析之外使用,因此处理错误的SFINAE规则永远不会被调用。但是这可以改变为使用Derived
作为重载解析的一部分:
template<typename T>
class DetectX
{
template<typename U>
struct Derived : U, Fallback { };
template<typename U>
static ArrayOfOne & func(Check<int Fallback::*, &Derived<U>::X> *);
template<typename U>
static ArrayOfTwo & func(...);
public:
enum { value = sizeof(func<T>(0)) == 2 };
};
Derived<T>
模板只有在尝试实例化第一个func()
过载时才被实例化,所以为什么我仍然得到错误,即使是修改后的版本?下面是一个例子:
$ g++ --version | head -n1
g++ (GCC) 4.8.2
$ g++ -c demo.cxx
demo.cxx: In instantiation of 'struct DetectX<int>::Derived<int>':
demo.cxx:16:53: required by substitution of 'template<class U> static char (& DetectX<T>::func(DetectX<T>::Check<int DetectX<T>::Fallback::*, (& DetectX<T>::Derived<U>::X)>*))[1] [with U = U; T = int] [with U = int]'
demo.cxx:24:31: required from 'class DetectX<int>'
demo.cxx:27:25: required from here
demo.cxx:7:12: error: base type 'int' fails to be a struct or class type
struct Derived : U, Fallback { };
^
您可以使用:(https://ideone.com/LArNVO)
#include <cstdint>
#include <type_traits>
#define DEFINE_HAS_MEMBER(traitsName, memberName)
template <typename U>
class traitsName
{
private:
struct Fallback { int memberName; };
struct Dummy {};
template<typename T, bool is_a_class = std::is_class<T>::value>
struct identity_for_class_or_dummy { using type = Dummy; };
template<typename T>
struct identity_for_class_or_dummy<T, true> { using type = T; };
template <typename Base>
struct Derived : Base, Fallback {};
template<typename T, T> struct helper;
template<typename T>
static std::uint8_t
check(helper<int (Fallback::*),
&Derived<typename identity_for_class_or_dummy<T>::type>::memberName>*);
template<typename T> static std::uint16_t check(...);
public:
static
constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint16_t);
}
DEFINE_HAS_MEMBER(has_foo, foo);
// Now test it:
class C{ public: int foo; };
class D : public C {};
class E {};
static_assert(has_foo<C>::value, "");
static_assert(has_foo<D>::value, "");
static_assert(!has_foo<E>::value, "");
static_assert(!has_foo<int>::value, "");
你可以理解为什么它失败在你的情况下,以下问题是什么是确切的"直接上下文"在c++ 11标准中提到的SFINAE适用?
简而言之,SFINAE适用于Derived<U>::X
,但不适用于Derived<U>
(在您的情况下是病态的)。
相关文章:
- 检查某些类型是否是模板类 std::optional 的实例化
- 在 c++ 中的模板实例化中使用带有构造函数的类作为类型参数
- 实例化模板时,我是否必须显式显示参数包中的类型?
- 在实例化之前推断函数模板的返回类型
- 对象实例化与类型C++
- 使用用户定义的类型 UDT 实例化 std::atomic<>。如果 UDT 具有虚函数,则 l 墨水将失败。为什么?
- 根据实例化点期望不同的类型
- 类模板实例化中的类型转换
- 实例化具有不完整类型的类模板格式不正确(如果该类型是在之后定义的)
- 实例化多种类型的成员函数模板
- C++ 多态模板类,模板类型对象的实例化
- 从模板实例化/类型推断中查找错误消息的实际来源
- MPL地图实例化类型
- SFINAE将实例化类型限制为std::chrono::duration类型
- 实例化类型模板化类的非类型模板化成员函数
- 使用大括号初始化列表或传统的 ctor 语法实例化类型
- 何时检查C++模板实例化类型
- 使LLDB将地址重新解释为指向模板实例化类型对象的指针
- 标准::shared_ptr 失去常量的实例化类型
- c++模板:我可以/如何使用结构体作为模板的实例化类型