c++ is_member_pointer implementation
c++ is_member_pointer implementation
在 c++ std 库中,is_member_pointer 实现为
template<typename _Tp>
struct __is_member_pointer_helper
: public false_type { };
template<typename _Tp, typename _Cp>
struct __is_member_pointer_helper<_Tp _Cp::*>
: public true_type { };
/// is_member_pointer
template<typename _Tp>
struct is_member_pointer
: public __is_member_pointer_helper<typename remove_cv<_Tp>::type>::type
{ };
有人可以解释一下_Cp是如何推断的吗? 它就像一个魔术。
指向成员的指针的类型是Type Class::*
,其中Type
是指向的对象类型或函数类型。例如,如果为模板提供int C::*
,编译器可以通过检查指向成员的指针的类型并查看类类型C
来简单地推断类类型。它还将以相同的方式推断出指向的类型int
。它的工作方式与我们人类的工作方式非常相似。通常,我们称这种技术模式匹配,您可能从正则表达式中熟悉它。
正式:
[温度扣除类型]/3.2:
指向成员的指针类型包括指向的类对象的类型和指向的成员的类型。
[温度扣除类型]/8:
如果 P 和 A 具有以下形式之一,则可以推导出模板类型参数 T、模板模板参数 TT 或模板非类型参数 i:
- [截图]
T T::*
- [截图]
其中 [温度扣除类型]/1:
可以在几个不同的上下文中推导模板参数,但在每种情况下,将根据模板参数指定的类型(称为 P)与实际类型(称为 A)进行比较,并尝试查找模板参数值(类型参数的类型、非类型参数的值、 或模板参数的模板),这将使 P 在替换推导值(称为推导的 A)后与 A 兼容。
几年前,我对模板专业化基本上C++误解与您现在的误解相同。
其他答案很好,但我认为它们不会真正帮助我理解正在发生的事情。所以,假设你和我一样遭受了同样的误解,让我试着解释一下我是如何最终正确思考的:
当时,我的直觉理解错误地告诉我,术语"专业化"意味着"专业模板"应该以某种方式比"原始模板"具有更少的模板参数。这个假设是由这样一个事实驱动的,即几乎每个试图解释专业化如何工作的教程代码都以类似示例开始
。template <class T> // <-- one parameter
class MyClass { ... };
template <> // <-- zero parameters
class MyClass<int> { ... };
现在,你的is_member_pointer
例子是一个反例,表明这根本不是真的。
我的整个误解始于使用错误的术语。您可能已经注意到,上面我在"专用模板"和"原始模板"周围加上了引号?我这样做是因为这是错误的,但那是我当时使用的词。
没错,只有一个模板。说有两个模板是错误的,一个是原始模板,一个是专用模板。在我的示例中
template <class T>
class MyClass { ... };
是模板,而
template <>
class MyClass<int> { ... };
是同一模板的专用化。
使它成为专业化的原因是使用类名背后的<int>
。就是这样!
这是同一模板的另一个有效专用化:
template <class... Types>
struct many_to_one { ... };
template <class A, class B, class C, class D> // <-- four parameters, could be even more
class MyClass<many_to_one<A, B, C, D>> { ... };
如您所见,专业化的模板参数比实际模板多得多。只要专用化类型的数量(本例中的一种类型,即many_to_one<A, B, C, D>
)与实际模板的模板参数数量匹配,这是完全有效的。
现在,如果您在任何地方使用MyClass<int>
,例如用于声明该类型的变量,编译器会做什么?
它查看了模板及其所有专业。
首先要注意的是:在这个例子中,只有一个模板参数,像MyClass<int, double, short, float>
这样的东西无法编译,即使有一个有四个参数的专用化!但这四个参数适用于专业化,而不是模板。
当编译器遍历所有专用化并发现
template <class A, class B, class C, class D>
class MyClass<many_to_one<A, B, C, D>> { ... };
它必须问自己"是否有任何类型A, B, C, D
使给定的类型(int
)等于专业化类型many_to_one<A, B, C, D>
?答案是否定的,所以它进入下一个专业化:
template <>
class MyClass<int> { ... };
它再次问自己"是否有任何类型<empty list here>
使给定的类型(int
)等于专业化类型int
?显然,是的!由于没有更好的匹配专业,它选择了这个。
相反,如果您有例如MyClass<double>
,两个专业的两个问题都产生"否"作为答案,因此将选择"基本"模板。
所以,最后回答你最初的问题:如果你写例如
std::is_member_pointer<decltype(&std::string::size)>
编译器查看专用化并看到"哦,看。如果我把_Tp = size_t
和_Cp = std::string
那么给定的类型decltype(&std::string::size)
等于专业化类型_Tp _Cp::*
,所以我选择那个专业化(碰巧继承自std::true_type
)"。
但是如果你写例如
std::is_member_pointer<int>
然后它找不到任何类型供_Tp
和_Cp
使_Tp _Cp::*
等于int
,因此它放弃了该专用化并选择"基本"模板(恰好继承自std::false_type
)。
它没有什么神奇的。它是简单的专用化,每当为类成员实例化模板时,_Cp
都会被推导出为包含类。
它是选择最佳可用专业化的一般情况的应用。
- Softmax Implementation in C++
- 在陈述"Implementation-defined"时,什么样的软件是"Implementation"的一部分?究竟什么是"Implementation"?
- 对于代理容器上的迭代器来说,"least bad implementation"可能是什么?
- STL binary_search() implementation
- Android Studio 3.1.2 - 无法运行C++子例程"No implementation found for Java.lang.String..."
- Vivado HLS implementation of RISCV
- C++ Class implementation
- c++ is_member_pointer implementation
- shared_mutex C++11 implementation
- VC++ implementation of std::promise
- libc++ implementation of std::condition_variable_any
- Paypal implementation...c++
- Boost Mutex implementation for Windows
- Implementation of mergesort
- C++ `Timer` class implementation
- BFS implementation
- C++ NTP Server implementation
- Low level implementation of bitwise Mod
- std::list implementation&pointer arithemetic.
- SIMD Implementation of std::nth_element