我創建了一個簡單的模板函式來生成一個 T 型別的亂數(我需要 int 或 float),范圍為 [low, high),如下所示:
template <typename T>
T randm(T low, T high)
{
static std::random_device seeder;
static std::mt19937 gen(seeder());
std::uniform_real_distribution<T> dis(low, high);
return dis(gen);
}
但是,當我嘗試將其稱為:
int r = randm<int>(0, 10);
我收到錯誤訊息:“靜態斷言失敗:result_type 必須是浮點型別”。
我發現如果我使用uniform_real_distribution<>而不是uniform_real_distribution<T>,它可以作業,但我不確定為什么(如果我沒有弄錯的話,uniform_real_distribution<>默認為我不需要的兩倍)。
uj5u.com熱心網友回復:
對于整數型別,有std::uniform_int_distribution。您必須應用if constexpr或使用 SFNIAE(具有型別特征)來分別處理浮點和積分。順便提一句。std::uniform_real_distribution 中有一個注釋:如果這不是 float、double 或 long double 之一,則效果未定義。(“this”涉及模板型別。)
SFINAE 區分的兩個獨立功能:
#include <iostream>
#include <random>
template <typename T,
std::enable_if_t<std::is_integral_v<T>, int> = 0
>
T randm(T low, T high)
{
static std::random_device seeder;
static std::mt19937 gen(seeder());
std::uniform_int_distribution<T> dis(low, high);
return dis(gen);
}
template <typename T,
std::enable_if_t<std::is_floating_point_v<T>, int> = 0
>
T randm(T low, T high)
{
static std::random_device seeder;
static std::mt19937 gen(seeder());
std::uniform_real_distribution<T> dis(low, high);
return dis(gen);
}
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(std::cout << randm(0, 10) << std::endl);
DEBUG(std::cout << randm(0.0f, 10.0f) << std::endl);
}
輸出:
std::cout << randm(0, 10) << std::endl;
4
std::cout << randm(0.0f, 10.0f) << std::endl;
9.05245
在coliru上進行現場演示
使用if constexpr(至少需要 C 17):
#include <iostream>
#include <random>
template <typename T>
T randm(T low, T high)
{
static std::random_device seeder;
static std::mt19937 gen(seeder());
if constexpr (std::is_integral_v<T>) {
std::uniform_int_distribution<T> dis(low, high);
return dis(gen);
}
if constexpr (std::is_floating_point_v<T>) {
std::uniform_real_distribution<T> dis(low, high);
return dis(gen);
}
return T(); // ERROR?
}
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(std::cout << randm(0, 10) << std::endl);
DEBUG(std::cout << randm(0.0f, 10.0f) << std::endl);
}
輸出:
std::cout << randm(0, 10) << std::endl;
7
std::cout << randm(0.0f, 10.0f) << std::endl;
3.51174
在coliru上進行現場演示
受Jarod42s 評論的啟發,另一個 C 11 解決方案:
#include <iostream>
#include <random>
#include <type_traits>
template <typename T>
T randm(T low, T high)
{
static std::random_device seeder;
static std::mt19937 gen(seeder());
typename std::conditional<std::is_integral<T>::value,
std::uniform_int_distribution<T>,
std::uniform_real_distribution<T>
>::type dis(low, high);
return dis(gen);
}
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(std::cout << randm(0, 10) << std::endl);
DEBUG(std::cout << randm(0.0f, 10.0f) << std::endl);
}
輸出:
std::cout << randm(0, 10) << std::endl;
2
std::cout << randm(0.0f, 10.0f) << std::endl;
4.36778
在coliru上進行現場演示
Jarod42還指出了這種方法的另一個弱點:std::is_integral涵蓋任何整數型別(包括char和 even 的變體bool)但如果模板型別不是 short、int、long、long long 中的一個,則std::uniform_int_distribution實際上是未定義的, unsigned short、unsigned int、unsigned long 或 unsigned long long。
此答案中提供了一個更好的替代方法,用于在 c 中模板化亂數生成器。
uj5u.com熱心網友回復:
根據cppreference,uniform_real_distribution有這樣的宣告:
template< class RealType = double >
class uniform_real_distribution;
// ctor
explicit uniform_real_distribution( RealType a, RealType b = 1.0 );
因此,當您使用 form 時uniform_real_distribution<>,它實際上替換了RealTypeas double(從默認模板引數中獲得)。然而,當你使用uniform_real_distribution<T>,你實際上具體的RealType作為T(在你的樣品的情況下,這是int),從而導致了一些static_assert在執行檢查失敗uniform_real_distribution。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/361052.html
下一篇:不實體呼叫函式到可變引數模板
