我可以像命名空间一样使用 class 作用域,而不是在所有内容前加上 class 名称吗
Can I use class scope like a namespace instead of prefixing everything with the class name
所以在头文件里面我可以做
namespace X {
doThis();
}
在实现文件中我可以做到
namespace X {
doThis() { .... }
}
但是如果我有 class
class X {
public:
doThis();
};
我是否可以在实现文件中做这样的事情
class X {
doThis() { .... }
}
而不是 X::doThis() { .... }
?
有“Java hack”¹,您可以在其中“继承”class 以使其成员进入您的命名空间:
class MyUserType : /*protected|private*/ X {
void foo() {
doThis(); // works
}
}
当然这只适用于
- class 没有定义在继承时会干扰的额外(非静态)特性
- 您的调用代码在 class 中,可以继承类型
- 派生的 class 不是模板,因为两阶段查找再次使事情变得奇怪(尽管您可以使用
using
声明来减轻它们,在逐个名称的基础上)
Re: class 定义的静态数据 members/out
在评论中,您似乎主要对代码的简洁性有疑问。调查
Disclaimer: following examples largely copied from cppreference
inline
variables (c++17),这是关于命名空间级别的静态变量,同样适用于class成员:
constexpr/const 声明中的静态成员初始化。
如果整数或枚举类型的静态数据成员被声明为 const(而不是 volatile),它可以用一个初始化器初始化,其中每个表达式都是常量表达式,就在 class 定义中:
struct X
{
const static int n = 1;
const static int m{2}; // since C++11
const static int k;
};
const int X::k = 3;
constexpr 成员甚至需要在声明中包含初始化程序:
struct X {
constexpr static int arr[] = { 1, 2, 3 }; // OK
constexpr static std::complex<double> n = {1,2}; // OK
constexpr static int k; // Error: constexpr static requires an initializer
};
请注意,在某些情况下,您可能仍然需要 class 定义,但没有初始化程序:
若 const 非内联 (C++17 起)静态数据成员或 constexpr 静态数据成员 (C++11 起)(C++17² 前)为 odr-used,定义at 命名空间范围仍然是必需的,但它不能有初始化程序。即使冗余 (C++17 起),也可以提供定义。
struct X {
static const int n = 1;
static constexpr int m = 4;
};
const int *p = &X::n, *q = &X::m; // X::n and X::m are odr-used
const int X::n; // … so a definition is necessary
constexpr int X::m; // … (except for X::m in C++17)
¹ 最长的时间 Java 没有枚举,因此您可以在基础中定义静态常量 class 从中“继承”以获取常量。
² 如果静态数据成员声明为 constexpr,则它是隐式内联的,不需要在命名空间范围内重新声明。这种没有初始化器的重新声明(如上所示以前是必需的)仍然允许,但已弃用。
所以在头文件里面我可以做
namespace X {
doThis();
}
在实现文件中我可以做到
namespace X {
doThis() { .... }
}
但是如果我有 class
class X {
public:
doThis();
};
我是否可以在实现文件中做这样的事情
class X {
doThis() { .... }
}
而不是 X::doThis() { .... }
?
有“Java hack”¹,您可以在其中“继承”class 以使其成员进入您的命名空间:
class MyUserType : /*protected|private*/ X {
void foo() {
doThis(); // works
}
}
当然这只适用于
- class 没有定义在继承时会干扰的额外(非静态)特性
- 您的调用代码在 class 中,可以继承类型
- 派生的 class 不是模板,因为两阶段查找再次使事情变得奇怪(尽管您可以使用
using
声明来减轻它们,在逐个名称的基础上)
Re: class 定义的静态数据 members/out
在评论中,您似乎主要对代码的简洁性有疑问。调查
Disclaimer: following examples largely copied from cppreference
inline
variables (c++17),这是关于命名空间级别的静态变量,同样适用于class成员:
constexpr/const 声明中的静态成员初始化。
如果整数或枚举类型的静态数据成员被声明为 const(而不是 volatile),它可以用一个初始化器初始化,其中每个表达式都是常量表达式,就在 class 定义中:
struct X { const static int n = 1; const static int m{2}; // since C++11 const static int k; }; const int X::k = 3;
constexpr 成员甚至需要在声明中包含初始化程序:
struct X { constexpr static int arr[] = { 1, 2, 3 }; // OK constexpr static std::complex<double> n = {1,2}; // OK constexpr static int k; // Error: constexpr static requires an initializer };
请注意,在某些情况下,您可能仍然需要 class 定义,但没有初始化程序:
若 const 非内联 (C++17 起)静态数据成员或 constexpr 静态数据成员 (C++11 起)(C++17² 前)为 odr-used,定义at 命名空间范围仍然是必需的,但它不能有初始化程序。即使冗余 (C++17 起),也可以提供定义。
struct X { static const int n = 1; static constexpr int m = 4; }; const int *p = &X::n, *q = &X::m; // X::n and X::m are odr-used const int X::n; // … so a definition is necessary constexpr int X::m; // … (except for X::m in C++17)
¹ 最长的时间 Java 没有枚举,因此您可以在基础中定义静态常量 class 从中“继承”以获取常量。
² 如果静态数据成员声明为 constexpr,则它是隐式内联的,不需要在命名空间范围内重新声明。这种没有初始化器的重新声明(如上所示以前是必需的)仍然允许,但已弃用。