我正在开发一个 C++ 项目,在该项目中我实现了一个
RandomEngineWrapper
类,以使用 std::variant
封装各种随机数引擎。但是,当我尝试将此包装器与 std::visit
结合使用时遇到编译错误。
no matching function for call to 'std::variant<std::linear_congruential_engine<unsigned int, 16807, 0, 2147483647>, std::linear_congruential_engine<unsigned int, 16807, 0, 2147483647>, std::linear_congruential_engine<unsigned int, 48271, 0, 2147483647>, std::mersenne_twister_engine<unsigned int, 32, 624, 397, 31, 2567483615, 11, 4294967295, 7, 2636928640, 15, 4022730752, 18, 1812433253>, std::mersenne_twister_engine<long long unsigned int, 64, 312, 156, 31, 13043109905998158313, 29, 6148914691236517205, 17, 8202884508482404352, 37, 18444473444759240704, 43, 6364136223846793005>, std::subtract_with_carry_engine<unsigned int, 24, 10, 24>, std::subtract_with_carry_engine<long long unsigned int, 48, 5, 12>, std::discard_block_engine<std::subtract_with_carry_engine<unsigned int, 24, 10, 24>, 223, 23>, std::discard_block_engine<std::subtract_with_carry_engine<long long unsigned int, 48, 5, 12>, 389, 11>, std::shuffle_order_engine<std::linear_congruential_engine<unsigned int, 16807, 0, 2147483647>, 256> >::variant(std::linear_congruential_engine<unsigned int, 16807, 0, 2147483647>)'
no matching function for call to 'visit(generateRandomIndex<std::vector<int> >(const std::vector<int>&, ENGINE, DISTRIBUTION)::<lambda(auto:27&)>, std::linear_congruential_engine<unsigned int, 16807, 0, 2147483647>&)'
#include <random>
#include <variant>
#include <vector>
#include <iostream>
enum class ENGINE {
DEFAULT_RANDOM_ENGINE,
MINSTD_RAND0,
MINSTD_RAND,
MT19937,
MT19937_64,
RANLUX24_BASE,
RANLUX48_BASE,
RANLUX24,
RANLUX48,
KNUTH_B,
RANDOM_DEVICE
};
enum class DISTRIBUTION {
UNIFORM_INT,
};
std::random_device rd;
class RandomEngineWrapper {
private:
std::variant<
std::default_random_engine,
std::minstd_rand0,
std::minstd_rand,
std::mt19937,
std::mt19937_64,
std::ranlux24_base,
std::ranlux48_base,
std::ranlux24,
std::ranlux48,
std::knuth_b
> engine_variant;
public:
template <typename T>
RandomEngineWrapper(T&& rng) : engine_variant(std::forward<T>(rng)) {}
template <typename T>
T& get() {
return std::get<T>(engine_variant);
}
};
RandomEngineWrapper getEngine(ENGINE engine) {
switch (engine) {
case ENGINE::DEFAULT_RANDOM_ENGINE:
return RandomEngineWrapper(std::default_random_engine(rd()));
case ENGINE::MINSTD_RAND0:
return RandomEngineWrapper(std::minstd_rand0(rd()));
case ENGINE::MINSTD_RAND:
return RandomEngineWrapper(std::minstd_rand(rd()));
case ENGINE::MT19937:
return RandomEngineWrapper(std::mt19937(rd()));
case ENGINE::MT19937_64:
return RandomEngineWrapper(std::mt19937_64(rd()));
case ENGINE::RANLUX24_BASE:
return RandomEngineWrapper(std::ranlux24_base(rd()));
case ENGINE::RANLUX48_BASE:
return RandomEngineWrapper(std::ranlux48_base(rd()));
case ENGINE::RANLUX24:
return RandomEngineWrapper(std::ranlux24(rd()));
case ENGINE::RANLUX48:
return RandomEngineWrapper(std::ranlux48(rd()));
case ENGINE::KNUTH_B:
return RandomEngineWrapper(std::knuth_b(rd()));
case ENGINE::RANDOM_DEVICE:
default:
return RandomEngineWrapper(std::mt19937(rd())); // Default case
}
}
auto getDistribution(DISTRIBUTION distribution, int size) {
switch (distribution) {
case DISTRIBUTION::UNIFORM_INT:
return std::uniform_int_distribution<>(0, size - 1);
default:
return std::uniform_int_distribution<>(0, size - 1); // Default case
}
}
template <typename Container>
int generateRandomIndex(const Container& container, ENGINE engineChoice, DISTRIBUTION distributionChoice) {
auto engineWrapper = getEngine(engineChoice);
auto dist = getDistribution(distributionChoice, container.size());
int index = 0;
std::visit([&](auto& engine) {
index = dist(engine);
}, engineWrapper.get<std::default_random_engine>());
return index;
}
int main() {
std::vector<int> myVector = {1, 2, 3, 4, 5};
int index = generateRandomIndex(myVector, ENGINE::MT19937, DISTRIBUTION::UNIFORM_INT);
std::cout << "Random index: " << index << std::endl;
return 0;
}
std::visit
函数中的generateRandomIndex
调用会产生错误:
no matching function for call to 'visit(generateRandomIndex<std::vector<int> >(const std::vector<int>&, ENGINE, DISTRIBUTION)::<lambda(auto:27&)>, std::linear_congruential_engine<unsigned int, 16807, 0, 2147483647>&)'
此外,在尝试使用各种随机引擎初始化
std::variant
时,我收到与 RandomEngineWrapper
构造函数相关的错误。
为什么我会收到这些错误,以及如何正确使用 std::variant 和 std::visit 来实现包装各种随机引擎并使用它们生成随机索引的目标?
###附加信息:###
std::variant
来包装不同类型的随机数引擎。RandomEngineWrapper
类旨在抽象不同随机引擎的细节。关于
std::variant
构造函数的错误是由于变体中有两份 std::linear_congruential_engine<unsigned int, 16807, 0, 2147483647>
造成的,一份来自 std::default_random_engine
,另一份来自 std::minstd_rand0
。从变体中删除 std::default_random_engine
即可修复该问题。
std::visit()
调用中的错误是因为它期望一个变体作为第二个参数,而不是实际的引擎类型。这可以通过向 RandomEngineWrapper
添加一个调用 std::visit
的成员函数来解决(基于 C++26 中的 std::variant::visit()
):
template <typename Visitor>
decltype(auto) RandomEngineWrapper::useEngine(Visitor&& vis) {
return std::visit(std::forward<Visitor>(vis), engine_variant);
}
可以在
generateRandomIndex()
中使用,如下所示:
int index;
engineWrapper.useEngine([&](auto& engine) {
index = dist(engine);
});