![](/img/trans.png)
[英]Qt C++; How to address a certain textfield, depending on user input
[英]How to declare a C++ constructor depending on user input?
我正在学习 C++ 并偶然发现了一个我不知道如何解决的问题。 我有一个概率分布的 class 层次结构。 我要求用户输入概率分布的名称(例如"uniform"
)及其相关参数,我将其存储为表单的元组
std::tuple<std::string, double, double>
然后我想调用对应概率分布class的构造函数,例如
continuous_distribution *random_uniform = new uniform{0.0,1.0};
但是,我不确定如何将 map 作为 C++ 字符串(元组的第一个元素)给出的分布名称传递给适当的构造函数。 我认为不可能直接将字符串转换为构造函数或成员 function。 我尝试使用if
语句检查给定名称并调用相应的构造函数,但这遇到identifier "x" is undefined
问题,显然是因为这将构造函数的 scope 限制为仅 if 语句。 这个问题有解决方案吗?
如果你真的想在这里使用动态 class 层次结构,一个简单的工厂 function 就可以了。
#include <string_view>
#include <memory>
struct distribution {
virtual float generate() = 0;
virtual ~distribution() = default;
};
struct uniform : distribution {
uniform(float, float);
float generate() final;
};
struct normal : distribution {
normal(float, float);
float generate() final;
};
std::unique_ptr<distribution> make_distribution(std::string_view name,
float x,
float y)
{
// for a large amount of different names, using a
// std::unordered_map<std::string, distribution*(*)(float,float)>
// may be more efficient than an if/else chain
if (name == "uniform") {
return std::make_unique<uniform>(x, y);
}
else if (name == "normal") {
return std::make_unique<normal>(x, y);
}
else {
return nullptr;
}
}
但是,我也会考虑不同的方法,例如使用不同分布的std::variant
,或者简单地使用std::function
或 function 指针,假设分布只有一个虚拟 ZC1C424Z0768E68394F11C
我可能会使用unordered_map
在分布的文字名称和能够使用该分布生成随机数的 object 之间进行映射。
在这种特殊情况下,我会避免运行时多态性——因为处理随机数生成的人通常痴迷于速度,而动态调度会带来一些开销。
以下是我会考虑的构建块:
static
- 或thread_local
如果这将是多线程的。 首先是 prng prng()
function 和一些分布示例:
#include <algorithm>
#include <functional>
#include <iostream>
#include <random>
#include <type_traits>
#include <unordered_map>
auto& prng() {
thread_local std::mt19937 instance(std::random_device{}());
return instance;
}
auto& uniform() {
thread_local std::uniform_real_distribution<double> instance;
return instance;
}
auto& normal() {
thread_local std::normal_distribution<double> instance;
return instance;
}
auto& exponential() {
thread_local std::exponential_distribution<double> instance;
return instance;
}
然后是 map。 它有点混乱,但遵循一个模式:
using gen_sig = double (*)(); // the signature of the returned generators
// A map from clear text name to a lambda that reads distribution parameters,
// sets them in the selected distribution and returns another lambda, wrapping
// a call to distribution(prng)
std::unordered_map<std::string, gen_sig (*)(std::ostream&, std::istream&)>
gen_factories{
{"uniform", [](std::ostream& os, std::istream& init) -> gen_sig {
using ptype = std::remove_reference_t<decltype(uniform())>::param_type;
os << "min max> ";
double min, max;
init >> min >> max;
uniform().param(ptype(min, max)); // set params
return [] { return uniform()(prng()); };
}},
{"normal", [](std::ostream& os, std::istream& init) -> gen_sig {
using ptype = std::remove_reference_t<decltype(normal())>::param_type;
os << "mean stddev> ";
double mean, stddev;
init >> mean >> stddev;
normal().param(ptype(mean, stddev)); // set params
return [] { return normal()(prng()); };
}},
{"exponential", [](std::ostream& os, std::istream& init) -> gen_sig {
using ptype = std::remove_reference_t<decltype(exponential())>::param_type;
os << "lambda> ";
double lambda;
init >> lambda;
exponential().param(ptype(lambda)); // set params
return [] { return exponential()(prng()); };
}},
};
与用户的交互可能如下所示:
int main() {
std::string dist;
while(std::cout << "Select distribution> " && std::cin >> dist) {
if(auto it = gen_factories.find(dist); it != gen_factories.end()) {
// get a generator
auto gen = it->second(std::cout, std::cin);
// print 10 numbers using the selected distribution
for(int i = 0; i < 10; ++i) std::cout << gen() << '\n';
} else {
std::cout << "ERROR: Distribution \"" << dist << "\" not implemented.\n";
}
}
}
示例 session:
Select distribution> exponential
lambda> 0.5
0.261241
0.0869284
1.73573
5.00439
1.68901
2.96613
0.583754
0.223562
0.2828
0.146842
Select distribution> uniform
min max> 10 20
17.177
19.587
18.9658
14.5269
11.6994
13.7626
13.8706
19.0378
17.0001
17.4791
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.