C++;'的语法理解问题;使用'; 我阅读了一些用C++创建的项目的技术文档。我发现一行代码包含我不懂的语法: using c = char (& (cClass::* [1]) (cClass(*)[2]) &)[3];
我在这里看到使用关键字的C++;'的语法理解问题;使用'; 我阅读了一些用C++创建的项目的技术文档。我发现一行代码包含我不懂的语法: using c = char (& (cClass::* [1]) (cClass(*)[2]) &)[3];,c++,C++,我在这里看到使用关键字的。这意味着我们要处理一个别名,但这一行做什么呢?我怎么能理解呢?我认为这会创建一个命名别名c,并将右侧表达式的结果赋给它。但是这个表达式是什么呢?下面是如何一步一步地读取您的类型。 为了清楚起见,下面我们声明一个变量x T x[1] x是类型为T cClass::* x[1] x是指向cClass内部成员的指针数组(长度为1) V (cClass::* x[1]) (U) x是指向cClass内部成员函数的指针数组(长度为1)。所述成员函数将U作为参数,并返回V V
。这意味着我们要处理一个别名,但这一行做什么呢?我怎么能理解呢?我认为这会创建一个命名别名c
,并将右侧表达式的结果赋给它。但是这个表达式是什么呢?下面是如何一步一步地读取您的类型。
为了清楚起见,下面我们声明一个变量x
T x[1]
x
是类型为T
cClass::* x[1]
x
是指向cClass
内部成员的指针数组(长度为1)
V (cClass::* x[1]) (U)
x
是指向cClass
内部成员函数的指针数组(长度为1)。所述成员函数将U
作为参数,并返回V
V (cClass::* x[1]) (U) &
x
是指向cClass
内部成员函数的指针数组(长度为1)。所述成员函数以U
为参数,返回V
,只能对左值调用
V & (cClass::* x[1]) (U) &
V (& (cClass::* x[1]) (U) &)[3]
x
是指向cClass
内部成员函数的指针数组(长度为1)。所述成员函数以U
为参数,返回对-V
的引用,并且只能对左值调用
V & (cClass::* x[1]) (U) &
V (& (cClass::* x[1]) (U) &)[3]
x
是指向cClass
内部成员函数的指针数组(长度为1)。所述成员函数以U
为参数,返回对V
数组(长度3)的引用,并且只能对左值调用
V & (cClass::* x[1]) (U) &
V (& (cClass::* x[1]) (U) &)[3]
最后,要得到你的实际类型
char (& (cClass::* x[1]) (cClass(*)[2]) &)[3]
我们选择V=char
和U=(cClass(*)[2])
,后者是指向cClass
的数组(长度2)的指针
V (cClass::* x[1]) (U)
更具可读性的备选方案:
using char3 = char [3];
using ptrTo2cClass = cClass(*)[2];
using ptrToMethod = char3 & (cClass::*) (ptrTo2cClass) &;
using c = ptrToMethod[1];
类型必须从中间开始解释(如果是变量声明,则变量名应该是中间的)。你向右走,直到到达终点。然后向左,直到你点击开头的或(
)。此时你要么解释了整个类型(然后你就完成了),要么你在(…)
的内部,在这种情况下,你丢弃它们并重复相同的过程(向右,然后向左)
由于这不是一个变量声明,您首先需要找到变量名的位置(如果它是一个变量名的话)。直观地说这更容易(一旦您获得了一些经验),但是一个不错的经验法则是从左边开始,直到您点击)
,或者(…)
,或者[…]
知道了这一点,我们可以将其转换为变量声明。我添加了x
作为变量名:
char (& (cClass::*x[1]) (cClass(*)[2]) &)[3];
现在我们可以开始读取类型了。首先我们向右走:
x
变量x
是…
x[1]
一个包含1个元素的数组,包含…
(没有其他东西在右边,向左走。)
cClass::*x[1]
指向类cClass
成员的指针,类型为…
(类::*x[1])
(左边没有其他内容,跳过括号。)
(cClass::*x[1])(………)&
一个带有一些参数的函数,&
-qualified1,返回…
(没有其他东西在右边,向左走。)
&(类::*x[1])(………)&
对…
(&(类::*x[1])(………)&)
(左边没有其他内容,跳过括号。)
(&(C类::*x[1])(………)&[3]
一个包含3个元素的数组,包含……
char(&(类::*x[1])(………)&[3]
char
s
我们结束了。函数参数的类型(cClass(*)[2]
)必须使用相同的过程单独解释。它是“指向大小为2的数组的指针,包含cClass
es”
1函数参数右侧的&
表示只能在左值上调用它(函数是“&
-qualified”)。缩小范围后,我刚刚看到了两个答案。然而,我确实写了一个新的答案,因为它展示了一种替代方法,你可以用STL类型的特征来缩小范围,从外部到内部
#include <type_traits>
#include <typeinfo>
#include <iostream>
class cClass {};
template <typename T>
struct Extract : std::false_type {};
template <typename TRet, typename TArg>
struct Extract<TRet (cClass::*)(TArg) &> : std::true_type {
using Ret = TRet;
using Arg = TArg;
};
int main()
{
using Type = char(&(cClass::* [1])(cClass(*)[2])&)[3];
std::cout << "Type=" << typeid(Type).name() << '\n';
static_assert(std::is_array_v<Type>);
using Type1 = decltype(std::declval<Type>()[0]);
std::cout << "array[" << std::extent_v<Type> << "] of " << typeid(Type1).name() << '\n';
static_assert(std::is_reference_v<Type1>);
using Type2 = decltype(std::remove_reference_t<Type1>());
std::cout << "ref to " << typeid(Type2).name() << '\n';
static_assert(std::is_member_function_pointer_v<Type2>);
std::cout << "member function pointer, cClass, taking " << typeid(Extract<Type2>::Arg).name() << ", returning " << typeid(Extract<Type2>::Ret).name() << '\n';
using FuncParam = cClass(*)[2]; // Pointer to array of 2 cClass
using FuncRet = char(&)[3]; // Reference to array of 3 chars
using Func = FuncRet(cClass::*)(FuncParam) &; // Member function for lvalue of cClass, taking FuncParam, returning FuncRet
using FuncArrayOne = Func[1]; // Array with one Func (WTF?)
static_assert(std::is_same_v<FuncArrayOne, Type>);
return 0;
}
#包括
#包括
#包括
类{};
模板
结构提取:std::false_type{};
模板
结构提取:std::true\u类型{
使用Ret=TRet;
使用Arg=TArg;
};
int main()
{
使用Type=char(&(类::*[1])(类(*)[2])&[3];
std::cout注意:这是我在上的答案的改编,因此我将其标记为社区维基,以避免获得重复的信誉点。(当然,如果您喜欢这个答案,请随意向上投票。)
下面的基于C++的模板允许编译器自己为您分解此声明的结构。
#include <iostream>
template <typename T>
struct introspect;
template <>
struct introspect<char> {
static std::ostream& prettyPrint(std::ostream& os) { return os << "char"; }
};
template <typename T>
struct introspect<T*> {
static std::ostream& prettyPrint(std::ostream& os) {
return os << "pointer to " << introspect<T>::prettyPrint;
}
};
template <typename T>
struct introspect<T&> {
static std::ostream& prettyPrint(std::ostream& os) {
return os << "reference to " << introspect<T>::prettyPrint;
}
};
template <typename T, typename Res, typename Arg1>
struct introspect<Res (T::*)(Arg1) &> {
static std::ostream& prettyPrint(std::ostream& os) {
return os << "pointer to lvalue member function of " << introspect<T>::prettyPrint
<< " taking (" << introspect<Arg1>::prettyPrint
<< ") and returning (" << introspect<Res>::prettyPrint << ')';
}
};
template <typename T, std::size_t N>
struct introspect<T[N]> {
static std::ostream& prettyPrint(std::ostream& os) {
return os << "array of " << N << " (" << introspect<T>::prettyPrint << ")";
}
};
class cClass;
template <>
struct introspect<cClass> {
static std::ostream& prettyPrint(std::ostream& os) {
return os << "cClass";
}
};
int main() {
using c = char (& (cClass::* [1]) (cClass(*)[2]) &)[3];
std::cout << introspect<c>::prettyPrint << '\n';
return 0;
}
在深入了解细节之前,让我告诉你们,<代码> [1 ] <代码>,代码> [ 2 ] <代码>,代码> > 3】/>代码>部分非常不寻常。这些真的是源代码,还是它们在文档中使用的“注释”,这些代码不意味着是C++代码?,但他们似乎很可疑,IMO。这行代码是在一个简单的主函数源代码中。开发人员将其描述为“使用指向成员函数的指针将其赋值给c”正如我所理解的,在阅读C++引用之后,指针指向1类方法。方法接受2个元素的数组,其中的类型作为指针指向类,但是在这样的表达式的两侧使用<代码>和<代码>运算符的目的是什么?最后?有人在故意装傻吗?池的回答解释了如何解读这一点,但诚实地说,即使是经验