C ++:模板类与两个类:效率

c++ : template class vs two classes : efficiency

本文关键字:两个 效率      更新时间:2023-10-16

>我尝试了两件事:

class RandDouble{
    public:
        RandDouble(double const& min_inclusive, double const& max_exclusive):
              mt_(std::random_device()),
              dist_(min_inclusive,max_exclusive)
         {}
        ~RandDouble(){}
        double get(){ return dist_(mt_); }
    private:
        std::mt19937_64 mt_;
        std::uniform_real_distribution<double> dist_;
};
class RandUnsignedInt{
    public:
        RandUnsignedInt(unsigned int const& min_inclusive, unsigned int const& max_inclusive):
              mt_(std::random_device()),
              dist_(min_inclusive,max_exclusive)
         {}
       ~RandUnsignedInt(){}
        unsigned int get(){ return dist_(mt_); }
    private:
        std::mt19937_64 mt_;
        std::uniform_int_distribution<unsigned int> dist_;
};

template<typename Type>
class Rand{
    public:
        Rand(Type const& min_inclusive, Type const& max_exclusive);/
        ~Rand();
        Type get();
    private:
        std::mt19937_64 mt_;
        std::uniform_real_distribution<double>* dist_double_;
        std::uniform_int_distribution<unsigned int>* dist_u_int_;
};
template<typename Type>
Rand<Type>::~Rand(){
    if(dist_double_){ delete dist_double_; }
    if(dist_u_int_){ delete dist_u_int_; }
}

.cpp文件:

template<>
Rand<double>::Rand(double const& min_inclusive, double const& max_exclusive):
    mt_(std::random_device()()),
    dist_double_(new std::uniform_real_distribution<double>(min_inclusive,max_exclusive)),
    dist_u_int_(NULL)
{}
template<>
Rand<unsigned int>::Rand(unsigned int const& min_inclusive, unsigned int const& max_exclusive):
    mt_(std::random_device()()),
    dist_double_(NULL),
    dist_u_int_(new std::uniform_int_distribution<unsigned int>(min_inclusive,max_exclusive))
{}
template<>
double Rand<double>::get(){ return (*dist_double_)(mt_); }
template<>
unsigned int Rand<unsigned int>::get(){ return (*dist_u_int_)(mt_); }

从实际的角度来看,模板解决方案与其他模板类更灵活,因为我可以执行以下操作:

template<typename Type>
classs C{
    /*some code*/
    private:
        Rand<Type> r;
};

所以我喜欢模板解决方案。但是当我检查调用Rand<double/unsigned int>::get()方法所需的时间时,我意识到它花费的时间是RandDouble::get()RandUnisignedint::get()的电话的两倍多。

它有一种方法可以通过调用方法保持模板方法的灵活性,该方法与具有两个不同类的方法一样高效。

问题可能是通过使用指向分布类的指针获得的间接寻址。尝试在没有指针的情况下直接使用这些类,或者最好做一些类似的事情

typename std::conditional<std::is_integral<Type>::value
                        , std::uniform_int_distribution<Type>
                        , std::uniform_real_distribution<Type> >::type _dist;

为了选择您需要的分发类型。(这只是为了给你一个提示,类型检查肯定可以改进)。


说明:上面的代码工作原理如下:std::conditional<(1),(2),(3)>就像类型的静态 if 语句一样。如果第一个字段中的校验(1)计算结果为 true,则它将第二个字段中的类型(2),否则(3)选取第三个字段中的类型。

如果模板参数 Type 是整数类型,则std::is_integral<Type>::value的计算结果为 true 。因此,您的分布类型将std::uniform_int_distribution<Type>通常需要的。

如果Type它不是整型类型(而是浮点型,但此处未选中),而是std::uniform_real_distribution<Type>用于分布的类型。

示例(此处测试):

#include<random>
#include<iostream>
template<typename Type>
struct UniformDistribution
{
    std::mt19937_64 mt_;
    typename std::conditional<std::is_integral<Type>::value
                            , std::uniform_int_distribution<Type>
                            , std::uniform_real_distribution<Type> >::type dist_;    
    Type get()
    {
        return dist_(mt_);
    }
};
int main()
{
     //produces uniformly distributed integer number in [0, numeric_limist<int>::max()]
     std::cout<<UniformDistribution<int>().get()<<std::endl;
     //produces uniformly distributed double number in [0,1]
     std::cout<<UniformDistribution<double>().get()<<std::endl;
}
#include<random>
template< class T >
struct TDist{};
template<> struct TDist<double> { std::uniform_real_distribution<double> dist_; };
template<> struct TDist<unsigned int> { std::uniform_int_distribution<unsigned int> dist_; };

template<typename Type>
class Rand : private TDist<Type> {
public:
    Rand(Type min_inclusive, Type max_exclusive) :
        mt_(std::random_device()),
        dist_(min_inclusive,max_exclusive)
    {}
    Type get(){ return dist_(mt_); }
private:
    std::mt19937_64 mt_;
};