由于我不是编程语言方面的专家,我很清楚这可能是一个愚蠢的问题,但是我可以告诉C#处理匿名方法和闭包,将它们变成匿名嵌套类的实例方法[1] ,实例化这个类,然后将委托指向那些实例方法.
看来这个匿名类只能被实例化一次(或者我错了吗?),那么为什么不让匿名类变为静态呢?
[1]实际上,看起来有一个闭包类和一个不捕获任何变量的匿名方法,我不完全理解其中的任何一个.
以下代码无法编译:
class C
{
private:
int m_x;
protected:
C(int t_x) : m_x(t_x) { }
};
class D : public C
{
public:
using C::C;
};
int main(int argc, char **argv)
{
D o(0);
}
Run Code Online (Sandbox Code Playgroud)
编译器的反对意见是声明了C的构造函数protected,这意味着我无法从中访问它main。换句话说,尽管using声明存在于public块中,但声明似乎仍随其拖动了标识符的原始可见性。
两个问题:
D?我有一堆如下代码:
int sign(MyEnum e)
{
switch(e)
{
case A:
case B:
return 1;
case C:
case D:
return -1;
default:
throw std::runtime_error("Invalid enum value");
}
}
int f(int a, int b, int c, MyEnum e)
{
const int sign = sign(e);
const int x = a * b - sign * c;
const int y = a + sign * c;
return x / y;
}
Run Code Online (Sandbox Code Playgroud)
这里的算术只是一个例子。实际的代码更复杂,但要点是sign根据枚举值是-1或1,并且我们进行了一堆计算,其中各种事情都乘以sign。(编辑:枚举值在编译时未知。)
我希望对这段代码进行优化,就像我写了以下代码一样:
int f(int a, int b, int …Run Code Online (Sandbox Code Playgroud) 在CLR中通过C#,Richter注意到在类声明中初始化字段,就像这样
class C {
int x = 3;
int y = 4;
public C() { ... }
public C(int z) { ... }
...
}
Run Code Online (Sandbox Code Playgroud)
导致在每个构造函数的开头插入语句,将语句设置为提供的值.因此,int x = 3;上面的行将负责两个单独的初始化 - 一个在无参数构造函数中,另一个在构造函数中接受int参数.
里希特继续说:
这意味着你应该知道代码爆炸[...]如果你有几个初始化的实例字段和许多重载的构造函数方法,你应该考虑在没有初始化的情况下定义字段,创建一个执行公共初始化的构造函数,并让每个构造函数显式调用公共初始化构造函数.这种方法将减少生成代码的大小.
我很难想象这会成为一个明显的问题,让我想知道我是否在这里遗漏了一些东西.例如,如果我们想象我们的类有十个构造函数和一百个字段,并且需要16个字节的本机机器代码来执行初始化,那么我们讨论的是总共16 kB生成的本机代码.当然,本世纪任何计算机上的内存都可以忽略不计,对吧?
我想使用泛型可以乘以一个小因子,但仍然对工作集的影响似乎很小.
问题:我在这里遗漏了什么,如果是的话,那是什么?
虽然我的问题主要是理论上的 - 我想测试我自己的理解 - 它也有点实用,因为初始化它们被声明的字段似乎比使用像Richter建议的集中式构造函数产生更可读的代码.
所以我遇到了一些奇怪的行为,我将其分解为以下最小的例子:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vec;
for(int i = 0; i < 1000; i++)
{
vec.push_back(2150000 * i);
if(i % 100 == 0) std::cout << i << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
使用命令使用gcc 7.3.0进行编译时
c++ -Wall -O2 program.cpp -o program
Run Code Online (Sandbox Code Playgroud)
我没有得到任何警告.运行该程序会产生以下输出:
0
100
200
300
400
500
600
700
800
900
1000
1100
1200
1300
[ snip several thousand lines of output ]
1073741600
1073741700
1073741800
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted (core …Run Code Online (Sandbox Code Playgroud) 假设我有一个std::any对象,该对象可能包含也可能不包含指向给定基类的某些派生类的指针B。有什么办法可以做些什么:
B *如果std::any对象包含可转换为的内容,则返回B *,或者返回似乎dynamic_cast并且std::any_cast每个都提供了此功能的一半,但是我看不到将两者结合在一起的任何方法。
我知道我可以通过多种方式来完成这项工作,包括显式枚举可转换为的每种类型B *,但这是所有DRY违规行为的源泉。
示例用例:
std::vector<std::any> setupTools(const std::string & confFile)
{
std::vector<std::any> myTools;
auto conf = parse(confFile);
for(std::string & wrenchInfo : conf["Wrenches"])
{
Wrench::setup(myTools, wrenchInfo);
}
for(std::string & hammerInfo : conf["Hammers"])
{
Hammer::setup(myTools, hammerInfo);
}
// 25 more kinds of tools
}
Factory1::init(const std::vector<std::any> & tools)
{
m_wrench = any_get<Wrench *>(tools);
m_hammer = any_get<Hammer *>(tools);
m_saw = any_get<Saw *>(tools);
}
Factory2::init(const …Run Code Online (Sandbox Code Playgroud) 假设我有一个std::map<int, std::string> myMap包含数据的
1. Red
2. Blue
3. Green
5. Fuchsia
6. Mauve
9. Gamboge
10. Vermillion
Run Code Online (Sandbox Code Playgroud)
还有一个std::map<int, std::string>::iterator it指向元素
5. Fuchsia
Run Code Online (Sandbox Code Playgroud)
我想做类似的事情(编造)
std::map<int, std::string> myHead = eject(myMap, myMap.begin(), it);
Run Code Online (Sandbox Code Playgroud)
这将导致myMap包含
5. Fuchsia
6. Mauve
9. Gamboge
10. Vermillion
Run Code Online (Sandbox Code Playgroud)
并myHead包含
1. Red
2. Blue
3. Green
Run Code Online (Sandbox Code Playgroud)
我可以通过做类似的事情来实现这一点
std::map<int, std::string> myHead;
myHead.insert(myMap.begin(), it);
myMap.erase(myMap.begin(), it);
Run Code Online (Sandbox Code Playgroud)
但这至少在某些情况下似乎不是最理想的,例如,如果我选择了一个点,以至于我只是从子树中分离出来。(我承认我实际上并没有仔细考虑这里算法复杂性的实际细节,但是如果我们想象一个值类型复制成本非常高的情况,那么很明显,上面的一般情况下不可能是最优的.)
问题:有没有办法std::map以最佳方式执行此操作,或者我是否必须编写自己的二叉搜索树来访问内部结构来完成此操作?
假设我有一个包含const成员联合的结构,如下所示:
struct S
{
// Members
const enum { NUM, STR } type;
union
{
const int a;
const std::string s;
};
// Constructors
S(int t_a) : type(NUM), a(t_a);
S(const std::string & t_s) : type(STR), s(t_s);
};
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.但现在说我想为这种类型编写一个复制构造函数.
它似乎不涉及做任何邪恶的事情,但由于我需要在成员初始化器中初始化const成员,我不会看到如何基于依赖于type成员的逻辑来执行此操作.
问题:
是否可以编写此构造函数?
如果不是,这本质上是一种语法上的疏忽,还是有一些根本原因导致语言无法支持这样的事情?
我正在使用可变宽度的通信格式。处理它的结构看起来像这样:
struct Header
{
int msgType = -1, len;
Header() { len = sizeof(*this); }
};
struct A : public Header
{
int x; char y;
A() { msgType = 1; len = sizeof(*this); }
};
// Further structs B, C, ... declared along the same lines
Run Code Online (Sandbox Code Playgroud)
我想要一个constexpr static成员Header::MAX_SIZE,它给出任何这些派生类的最大大小,例如,这样我就可以分配一个缓冲区,保证可以容纳任何此类数据包。所以我想做类似的事情
struct Header
{
int msgType = -1, len;
constexpr static std::size_t MAX_SIZE;
Header() { len = sizeof(*this); }
};
// ... declaration of subclasses ...
inline Header::MAX_SIZE …Run Code Online (Sandbox Code Playgroud) 我的理解是:
看来像下面这样的东西不应该编译,事实上在我的编译器上它不编译。
template<int n> struct S { };
template<int a, int b>
S<a * b> f()
{
return S<a * b>();
}
int main(int, char **)
{
f<50000, 49999>();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是,现在我尝试以下方法:
#include <numeric>
template<int n> struct S { };
template<int a, int b>
S<std::lcm(a, b)> g()
{
return S<std::lcm(a,b)>();
}
int main(int, char **)
{
g<50000, 49999>();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
g++、clang 和 MSVC 都会愉快地编译它,尽管事实上
如果 |m|、|n| 或 |m| 的最小公倍数,则行为未定义 和|n| 不能表示为 type 的值
std::common_type_t<M, N> …