Есть ли способ сохранить спецификатор типа в переменной? - PullRequest
1 голос
/ 07 июля 2019

Есть ли способ сохранить спецификатор типа в переменной?Я искал вокруг и нашел typeid и decltype, но ни один из них не работает так, как мне бы хотелось.decltype не генерирует переменные, а typeid обычно используется для typeid (). name ().

Поскольку typeid (). name () выводит спецификатор типа в виде const char *, который можно сохранить и передатьвокруг, есть ли функция для преобразования const char * обратно в спецификатор типа?Например:

int a = 1;
auto t = typeid(a).name();
some_function(t) b = 1; //gives int b

Я знаю, что decltype делает именно это, но не может «хранить» спецификатор типа.

В моем недавнем проекте я обнаружил любопытный случай, когда типАргумент функции может варьироваться при каждом вызове.Обычно с помощью шаблонов функций это можно сделать, но для этого нужно либо поместить весь код в заголовок, что недопустимо в этом проекте, либо использовать явную интантификацию, которая может запутаться, поскольку перечислить все типы сложно.Кроме того, написание нескольких перегрузок функций для каждого типа также довольно грязно.

Если есть способ сохранить спецификатор типа как переменную, то я могу использовать void * для передачи адреса ввода и передачипеременная, содержащая спецификатор типа в функцию, а затем приведение void * к ее исходному типу?

Каким-то образом typeid (). names () уже предлагает способ хранения и передачи типа переменной. Интересно,есть элегантный способ преобразовать его обратно в спецификатор типа без написания длинных списков "strcmp" или других ручных преобразований.

Спасибо!

Редактировать: Подробнее о моем проекте, функция используется какустановщик для закрытых членов класса, первый ввод - enum относительно идентификатора члена, второй - значение.Класс также может быть унаследован.Проект требует, чтобы в заголовке было как можно меньше кода.В этом проекте используется OpenCV.

В Header.h:

#include "some_other_custom_class.h"
#include <string>

enum BASE_PARA
{
    A,
    B,
    C
}
class Base
{
public:
    Base() = default;
    virtual ~Base() = default;

    //<sometype> may vary regarding the member
    virtual void Set(const int& id, const <sometype>& value);

private:
    int a;
    float b;
    map<std::string, double> c;
}

enum DERIVED_A_PARA
{
    D,
    E
}
class DerivedA : public Base
{
public:
    //inherit Set()
    virtual void Set(const int& id, const <sometype>& value) override;

private:
    map<int, <some_custom_class>> d;
    vector<double> e;
}

class DerivedB : public DerivedA //and so on
{
}

В Cpp.cpp:

void Base::Set(const int& id, const <sometype>& value)
{
    //processing the input regarding the private member

    //<do something here>

    switch(id)
    {
    default:
        break;
    case A:
        a = value;//which means in here <sometype> should be int
        break;
    case B:
        b = value;//<sometype> should be float
        break;
    case C:
        //<sometype> should be map<string, double>
        if (<some_code_to_ensure_value_is_not_empty>)
            return;
        c["first"] = value["first"];
        c["second"] = value["first"] + value["second"];
        break;
    }
}

void DerivedA::Set(const int& id, const <sometype>& value)
{
    //something like above
}

Я знаю, что шаблон функции хорош для этого, ноне могу использовать это, как сказано выше.Поэтому я надеялся заменить «sometype» на void * для указания на адрес и на const char *, сгенерированный из typeid (). Name () для обозначения фактического типа.Но я не могу найти хороший способ преобразовать const char * обратно в спецификатор типа.

1 Ответ

2 голосов
/ 07 июля 2019

Есть три варианта

  1. комплект перегрузки,
  2. шаблон функции или
  3. тип стирания

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

Лучшая ставка для " [a] типа аргумента функции [который] может варьироваться " - это шаблон функции, поскольку в основном это вариант использования шаблонов.

Если они не могут быть в (возможно) общедоступных заголовочных файлах проекта, тогда может сработать какой-то внутренний заголовок. Если код используется только в определенной точке, шаблон может быть определен внутри исходного файла (жертвуя возможностью повторного использования).


std::any в C ++ 17 - это своего рода синтаксический сахар для стирания типов, который может дать вам более элегантное стирание типов с исключениями std :: bad_any_cast, если вы приведете к типу, который не удерживается any .

void Base::Set(const int& id, std::any const& value)
{
    switch(id)
    {
        case static_cast<int>(BASE_PARA::A):
            this->a = std::any_cast<int>(value);
            break;
        // ... and so on ...
    }
}
...