Fairlight
Fairlight

Reputation: 31

Placing member functions inside definition

I'm in the process of moving a lot of oft-used functions into classes, and hit a snag that I can't explain. With the "STD::random-device rd" and "std::mt19937 gen(rd())" declarations in global-space everything works fine.

include <random>

std::random_device rd;
std::mt19937 gen(rd());

class randomGenerator
{
public:

    float getRandomFloat(float lowerLimit, float upperLimit)
    {
        std::uniform_real_distribution<>dist(lowerLimit, upperLimit);
        return (float)dist(gen);
    }
};
randomGenerator myGenerator;

But if I move the declarations into the class definition, the compiler complains...

include <random>

class randomGenerator
{
public:
    std::random_device rd;
    std::mt19937 gen(rd());
    float getRandomFloat(float lowerLimit, float upperLimit)
    {
        std::uniform_real_distribution<>dist(lowerLimit, upperLimit);
        return (float)dist(gen);
    }
};
randomGenerator myGenerator;

"E0757 member "randomGenerator::rd" is not a type name" and "E0304 no instance of overloaded function "std::uniform_real_distribution<_Ty>::operator() [with _Ty=double]" matches the argument list"

I've had similar trouble moving standalone variable declarations into other classes as well; seems almost hit-and-miss. Is there some reason why this doesn't always work? I can't see why some declarations (like above) will only work in global-space.

Upvotes: 3

Views: 95

Answers (1)

Fatih BAKIR
Fatih BAKIR

Reputation: 4715

For a quick fix, use brace initialization:

class randomGenerator
{
public:
    std::random_device rd;
    std::mt19937 gen{rd()};
    float getRandomFloat(float lowerLimit, float upperLimit)
    {
        std::uniform_real_distribution<>dist(lowerLimit, upperLimit);
        return (float)dist(gen);
    }
};

In your original definition, the compiler thinks gen is a member function returning a std::mt19937 that takes another function returning an instance of type rd, which does not exist. This is commonly known as most vexing parse.

Also, as Ted Lyngmo mentioned down in the comments, if you only use the std::random_device to seed gen once, you can get rid of the member variable and use a temporary random device to construct gen directly:

class randomGenerator
{
public:
    std::mt19937 gen{std::random_device{}()};
    ...
};

Upvotes: 10

Related Questions