Проблемы при попытке использовать автоматический тип C для атрибутов объекта (переменных-членов) и вывод возвращаемого типа std::bind

#c

#c

Вопрос:

У меня есть следующий код, который пытается сгенерировать случайную шестнадцатеричную цифру.

 #include <random>
#include <functional>


using std::mt19937;
using std::uniform_int_distribution;


class
RandomHexDigitGenerator
(
    public :

        // Other functions omitted for the sake of brevity.

        RandomHexDigitGenerator
        (
        );

        char
        generateRandomHexDigit
        (
        );


    private :

        mt19937                       * rng_p;

        mt19937::result_type            seed;

        uniform_int_distribution<int> * distribution_p;  // Map values onto range [0, 15]

        // The following declaration will cause a problem since
        // the compiler won't be able to deduce its type.

        auto                            rhvg;
);
 

Определения двух методов следующие;

 // Constructor for class.

RandomHexDigitGenerator::RandomHexDigitGenerator
(
)
{
    this->seed           = time(0);

    this->rng_p          = new mt19937(this->seed);

    this->distribution_p = new uniform_int_distribution<int>(0, 15);

    // The following line of code will also be problematic.

    this->rhvg           = std::bind(* this->distribution_p, * this->rng_p);
}


char
RandomHexDigitGenerator::generateRandomHexDigit
(
)
{
    int   randomHexValue;


    randomHexValue = this->rhvg();

    return(this->convertHexValueToHexDigit(randomHexValue));
}
 

Моя проблема с кодом заключается в операции привязки, которая выполняется в конструкторе. Я не знаю, каков его возвращаемый тип, поэтому я объявляю rhvg как auto . Проблема в том, что, насколько я понимаю, компилятор должен иметь возможность определять тип rhvg, когда он впервые сталкивается с ним в объявлении класса!

Итак, мой вопрос в том, как я могу решить эту проблему? Будет ли тип, возвращаемый операцией привязки, ужасным, и, следовательно, я даже не должен пытаться понять, что это такое? Должен ли я продолжать использовать auto, но другим способом? Является ли шаблонизация класса опцией или шаблонизация является сложным решением для не такой сложной проблемы?

В случае, если это имеет значение, я использую GNU g под Linux Mint версии 19.2, и вывод g -v команды выглядит следующим образом;

 Using built-in specs.
COLLECT_GCC=g  
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.4.0-6ubuntu1~16.04.10' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c  ,java,go,d,fortran,objc,obj-c   --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.10)
 

Наконец, мой Makefile использует переключатель -std=c 11 компилятора в правильном месте.

Заранее благодарю.

Комментарии:

1. Я предполагаю, что вы имеете в виду std::bind. Пожалуйста, добавьте, какой компилятор вы используете и какую версию C (если вы ее знаете). Как это выглядит, возвращаемый тип std::bind не является или не всегда был частью спецификации C . Кроме того, пожалуйста, добавьте то, что вы уже сделали, чтобы получить ответ.

2. Зачем вам использовать std::bind здесь, с объектами известного типа и вызовом, которым вы управляете? Просто вызывайте дистрибутив с генератором, когда вам нужно, нет?

3. Не имеет отношения к вопросу, но почему все пустые строки? Кроме того, вам не нужно писать this-> везде и не заключать возвращаемые выражения в скобки.

Ответ №1:

Ваш код намного более запутанный и подробный, чем мне удобно. Вот что я бы сделал:

 #include <random>
#include <ctime>
    
class RandomHexDigitGenerator
{
  public:
    char generateRandomHexDigit() {
        return static_cast<char>(dist(rng));
    }
  private:
    std::mt19937 rng{static_cast<std::mt19937::result_type>(std::time(0))};
    std::uniform_int_distribution<int> dist{0, 15};
};
 

Нет new , нет bind .

Возвращаясь к поставленному вопросу, у вас не может быть нестатического члена класса типа «неизвестный результат привязки». Вместо этого вы можете иметь std::function , но это не имеет никакого смысла, вот почему.

bind сохраняет свои аргументы путем копирования, поэтому, если вы сделаете это

 std::function<char(void)> rhvg;
rhvg = std::bind(distribution, rng);
 

вам больше не нужны distribution rng члены and, потому что они копируются в bind . Таким образом, вы можете создать их в конструкторе вместо этого.

 class RandomHexDigitGenerator
{
  public:
    char generateRandomHexDigit() {
       return rhvg();
    }
  private:
    std::function<char(void)> rhvg = std::bind(
      std::uniform_int_distribution<int>(0, 15),
      std::mt19937(static_cast<std::mt19937::result_type>(std::time(0)))
    );
};
 

но зачем для этого нужен класс? Вместо этого вы можете обернуть все в функцию:

 std::function<char(void)> makeRandomHexDigitGenerator() {
  return std::bind(whatever);
}