Написать метод с конечным типом возвращаемого значения для изменения в зависимости от вызова метода?

У меня есть класс под названием Eclipse с закрытым членом структуры, содержащим ~ 30 полей различных типов данных.

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

Поскольку структура содержит данные различных типов, я решил использовать auto ключевое слово с конечным типом возврата, основанным на шаблонном параметре. Мой заголовок метода ниже.

template<typename TheType>
auto getColumnData(TheType toGet, int fieldNum) -> decltype(toGet) {
// switch statement to return fields based on fieldNum
}

Если я хочу вернуть столбец, который является int, Я звоню getColumnData(0, 1);, Первый параметр используется только для определения типа возврата метода, а второй параметр определяет номер поля для возврата вызывающей стороне метода.

Теоретически, это приведет к типу возврата getColumnData() быть int и вернуть первый столбец (соответствующий первому полю) структуры. Но я получаю эту ошибку компиляции:

нет жизнеспособного преобразования из возвращенного значения типа ‘std :: string’ (он же basic_string)<char, char_traits<char>, распределитель<char>> ‘) в функцию, возвращаемую тип’ decltype (toGet) ‘(он же’ int ‘) `

Я понимаю, что если бы я вызвал этот метод с int в качестве первого параметра и номер поля, который соответствует полю, возвращающему std::stringБудут проблемы. Но, основываясь на проверках в других классах, этот случай никогда не произойдет.

Есть ли способ заставить мой компилятор принять этот код, даже если он может быть неправильным в определенных случаях?

Я знаю, что мог бы просто перегружать метод, но я бы предпочел не иметь несколько разных методов для одной и той же цели, если бы я мог понять, как выполнить задачу только в одном.

Кроме того, если мое понимание какой-либо из этой информации кажется неверным, пожалуйста, дайте мне знать. Я очень новичок в C ++, поэтому я просто изучаю эти функции по ходу дела.

0

Решение

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

Простое решение будет использовать std::variant (C ++ 17 или более поздняя версия) или boost::variant (C ++ 11 и выше) в качестве типа возвращаемого значения:

using FieldType = std:::variant<int, std::string>;

FieldType getColumnData(int fieldNum) {
// switch statement to return fields based on fieldNum
}

int i = std::get<int>(getColumnData(1));
std::string s = std::get<std::string>(getColumnData(2));

В противном случае вы должны будете сделать возвращаемый тип параметром шаблона, а не параметром метода:

template<typename TheType>
TheType getColumnData(int fieldNum) {
// switch statement to return fields based on fieldNum
}

Но затем вы сталкиваетесь с проблемой, что не все поля будут преобразованы в возвращаемый тип (не может вернуть std::string поле, когда int и т.д.), так что вы не можете просто switch на fieldNum так как он не оценивается во время компиляции.

У вас может возникнуть желание сделать номер поля параметром шаблона, чтобы он был постоянным во время компиляции, а затем специализироваться на нем:

template<const int FieldNum>
auto getColumnData() { return 0; };

template<> int getColumnData<1>() { return private_struct.Field1; }
template<> std::string getColumnData<2>() { return private_struct.Field2; }
// etc...

int i = getColumnData<1>();
std::string s = getColumnData<2>();

Но я получаю ошибки, когда пытаюсь сделать это на шаблонном методе класса («явная специализация в области без пространства имен»).

У вас может возникнуть соблазн сделать что-то подобное и надеяться, что компилятор оптимизирует неиспользуемые ветки:

template<const int FieldNum>
auto getColumnData() {
if (FieldNum == 1) return private_struct.Field1;
if (FieldNum == 2) return private_struct.Field2;
//etc...
return 0;
}

или же

template<const int FieldNum>
auto getColumnData()
{
switch (FieldNum) {
case 1: return private_struct.Field1;
case 2: return private_struct.Field2;
// etc...
}
return 0;
};

int i = getColumnData<1>();
std::string s = getColumnData<2>();

Но это тоже не работает (ошибки «непоследовательный вывод для типа авто возврата»).

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]