c++ - std::bind 需要默认构造函数

标签 c++ visual-studio-2012 c++11

我正在做一个学校项目(命名空间名称可能暗示,它是 2D 游戏),我创建了一个名为 RangeInt(Range) 的自定义类,它只包装了两个相同类型的变量,并创建了另一个名为 Randomizer 的类,它包装了C++11 标准随机数生成并使用 RangeInt 类指定我要生成数字的范围。

无论如何这是代码:

    namespace game{
    template<class _Type>
    //very simple class representing virtual Range
    //of type _Type(template argument) and storing
    //upper and lower bound
    class Range{
        public:
        typedef _Type TemplateParam;
        //value sto use of type _Type
        _Type first, second;

        //copy constructor:
        Range(const Range& rng)
        {
            first = rng.first;
            second = rng.second;
        }

        //move construct:
        Range(Range&& rng)
        {
            std::swap(*this, rng);
        }
        Range& operator=(const Range& range)
        {
            first = range.first;
            second = range.second;
            return *this;
        }
        Range& operator=(Range&& range)
        {
            std::swap(first, range.first);
            std::swap(second, range.second);
            return *this;
        }
        //constructor
        Range(_Type one, _Type two) : first(one), second(two) {}
        //returns two - one
        inline _Type getDifference() { return two - one; }
    };

    typedef Range<uint> RangeInt;
};

和随机发生器:

namespace game{
    template <class _RNG = xorshift>
    class Randomizer_RNG{
        typedef _RNG random_generator;
        RangeInt rng;
        random_generator mt;
        std::uniform_int_distribution<> dist;
        //reinitialize the dist variable so it actually knows the new range
        void _changeDist()
        {
            dist = std::uniform_int_distribution<>(rng.first, rng.second);
        }
        public:
        //default constructor, set rng to maximum range and initialize
        //the xorshift with seed being current time and specify the
        //range for uniform_int_distribution
        Randomizer_RNG()
        {
            rng = game::RangeInt(0, std::numeric_limits<game::uint>::max());
            dist = std::uniform_int_distribution<>(range.first, range.second);
            mt.seed(std::chrono::high_resolution_clock::now().time_since_epoch().count());
        }
        //do the same as constructor above but with specified range
        explicit Randomizer_RNG(RangeInt range) : rng(range)
        {
            dist = std::uniform_int_distribution<>(rng.first, rng.second);
            mt.seed(std::chrono::high_resolution_clock::now().time_since_epoch().count());
        }
        //copy constructor
        Randomizer_RNG(const Randomizer_RNG& lhs)
        {
            dist = lhs.dist;
            mt = lhs.mt;
            rng = lhs.rng;
        }
        //move constructor
        Randomizer_RNG(Randomizer_RNG&& lhs)
        {
            std::swap(*this, lhs);
        }
        //reseed with current time
        inline void seed()
        {
            mt.seed(std::chrono::high_resolution_clock::now().time_since_epoch().count());
        }
        //reseed with specified value
        inline void seed(unsigned long long newSeed)
        {
            mt.seed(newSeed);
        }
        //default operator()
        uint32 operator()()
        {
            return dist(mt);
        }
        //return value generated in range of
        //<fitWithin.first, fitWithin.second>
        uint32 operator()(RangeInt&& fitWithin)
        {
            decltype(dist) l_dist(fitWithin.first, fitWithin.second);
            return l_dist(mt);
        }
        //the same as above, but with rvalue reference
        uint32 operator()(RangeInt& fitWithin)
        {
            decltype(dist) l_dist(fitWithin.first, fitWithin.second);
            return l_dist(mt);
        }
        //change range with reference
        void changeRange(const RangeInt& rng)
        {
            this->rng = rng;
            _changeDist();
        }
        //the same as above but with rvalue reference
        void changeRange(RangeInt&& rng)
        {
            std::swap(this->rng, rng);
            _changeDist();
        }
        //set the upper bound of the range and update rng
        void setUpperBound(RangeInt::TemplateParam upBound)
        {
            rng.second = upBound;
            _changeDist();
        }
        //set the lower bound of the range and update rng
        void setLowerBound(RangeInt::TemplateParam lowBound)
        {
            rng.first = lowBound;
            _changeDist();
        }
        //copy assignment
        Randomizer_RNG& operator=(const Randomizer_RNG& lhs)
        {
            _RETURN_IF_THIS(lhs, *this);    //if (*this == lhs)    return *this;
            rng = lhs.rng;
            changeRange(rng);
            return *this;
        }
        //move assignment
        Randomizer_RNG& operator=(Randomizer_RNG&& lhs)
        {
            dist = std::move(lhs.dist);
            rng = std::move(lhs.rng);
            mt = std::move(lhs.mt);
            return *this;
        }
    };
    typedef Randomizer_RNG<> Randomizer;
    typedef Randomizer_RNG<std::mt19937> Randomizer_Twist;
};

但是当我这样做的时候

#include "randomizer.h"

int main()
{
    game::RangeInt rngI (14, 546);
    game::Randomizer rng = game::Randomizer(game::RangeInt(0, 100));
    auto func = std::bind(rng, rngI);
    std::cout << func();
    std::cin.get();
}

它弹出编译器错误:

error C2512: 'game::Range<_Type>' : no appropriate default constructor available
with  
[  
_Type=game::uint  
]

如果我尝试这样做:

#include "randomizer.h"

int main()
{
    game::RangeInt rngI (14, 546);
    game::Randomizer rng = game::Randomizer(game::RangeInt(0, 100));
    auto func = std::bind(&rng, rngI);
    std::cout << func();
    std::cin.get();
}

它说: 错误 C2679:二进制“<<”:未找到接受类型为“std::_Do_call_ret<_Forced,_Ret,_Funx,_Btuple,_Ftuple>::type”的右手操作数的运算符(或没有可接受的转换)

所以我想知道我是不是做错了什么,或者为什么 std::bind 需要我为 game::Range 使用默认构造函数。

如果我的问题不清楚或代码不清楚,请告诉我,我会尽力而为。

PS:我使用的是 Visual Studio 2012,因此未实现 Variadic 模板(例如 std::bind 有 378 个重叠)

最佳答案

成功

Randomizer_RNG(const Randomizer_RNG& lhs)
   : dist(lhs.dist), mt(lhs.mt), rng(lhs.rng)
{}

或者完全放弃这个构造函数:编译器生成的就足够了。

如所写,您的构造函数首先尝试默认构造 rng,然后再分配给它。但是,正如编译器告诉您的那样,Range 不提供默认构造函数。

关于c++ - std::bind 需要默认构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19412013/

相关文章:

c++ - 2 维数组的大小

c++ - std::map、多态和删除

C++ 在读取 Hex 和将 Hex 写入文件时遇到问题

c++ - MFC 中的全屏窗口

c++ - 如何将 vector 元素作为参数传递给可变参数模板函数?

c++ - 为什么 "default"是复制/移动构造函数或析构函数?

c++ - 静态常量成员初始化和模板(与静态函数相比)——这是如何工作的?

visual-studio - 每个 TFS 分支的自定义 Visual Studio 皮肤

.net - 如何将 .net 错误消息语言更改为英语

c++ - 为什么 std::get() 不能用于获取 vector 的成员?