LINUX.ORG.RU

Функция, меняющая тип возвращаемого значения в зависимости от переменной C++

 , ,


0

1

Всем добра и счастья:) Имеется вот такой вот код(пример):

#include <iostream>


using namespace std;

//if(flag) -> int foo(bool);
//else     -> double foo(bool);

auto foo(bool flag) ->decltype(flag ? 1 : 1.0)
{
    if(flag)    return 1;
    else        return 1.0;
}

int main()
{
    int a = foo(true);//должна вернуть тип int
    double b = foo(false);//соответственно double
    return 0;
}

Как видите, я добился такого поведения через дикий костыль в decltype. Как можно это записать более правильно и красиво?

★★

Последнее исправление: zamazan4ik (всего исправлений: 1)

Такая концепция не может быть красивой. Это как ты бы спросил какого цвета блёстками следует украшать говно.

Stahl ★★☆
()
Ответ на: комментарий от conalex

нет. Не олимпиада:) Просто интересно, как такое написать красиво. Я вот всё никак не могу придумать, что можно в decltype подставить такого вместо этих единичек. А как вы тут перегрузите? По возвращаемому значению что ли?:)

zamazan4ik ★★
() автор топика
Ответ на: комментарий от Stahl

концепция ужасна, тут Ваша правда. увидел бы такое в коде проекта - убил бы. Ну или проматерился. Но интерес сейчас важнее. Нет ли какого-нибуь способа сгенерировать обьект типа int\double и подсунуть его decltype?

zamazan4ik ★★
() автор топика

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

mashina ★★★★★
()

Как видите, я добился такого поведения

Неа (d — double), decltype работает не так. Тут только метапрограммирование и только во время компиляции, ну либо какой-нибудь variant-like тип.

xaizek ★★★★★
()
Ответ на: комментарий от zamazan4ik

Через специализацию, как обычно...

template<typename T> T One();

template<> int One<int>() { return 1; };
template<> double One<double>() { return 1.; };

...

auto b = One<double>();
mashina ★★★★★
()
Последнее исправление: mashina (всего исправлений: 2)
Ответ на: комментарий от mashina

а,так ...такое умею :) А что-нибудь иное есть? а значения, возвращаемые int() и double() равны 0 и 0.0 соответственно?

zamazan4ik ★★
() автор топика

В рантайме такое невозможно, ибо как оно будет делать приведение типов?

А в compile-time как-то так:

#include <iostream>
#include <iomanip>

int foo_true(bool flag)
{
	return 1;
}
float foo_false(bool flag)
{
	return 1.5;
}

#define foo(f) foo_##f(f)


int main()
{
	int a;
	float b;

	a=foo(true);
	b=foo(false);
	std::cout << int(a) << ", " << float(b) << std::endl;

	return 0;
}

Kroz ★★★★★
()
Ответ на: комментарий от Kroz

стоп. МОжет я чего-то не понимаю? Тогда как он делает в таком случае(пример):


template<typename T, typename V>
auto foo(T a, V b) -> decltype(a+b);

//----------------------------------

//тут берём коллекцию, из неё берём два рандомных элемента, и вызываем для них foo

zamazan4ik ★★
() автор топика
Ответ на: комментарий от zamazan4ik

Позабористей

#include<stdio.h>

template<bool>
struct Type{
    static double constexpr value = 2.0;
};

template<>
struct Type<true>{
    static int constexpr value = 1;                                                                                                                   
};

template<bool Flag>
decltype(Type<Flag>::value) One(){
    return Type<Flag>::value;
}

int main(){
    printf("int = %d\n", One<true>());
    printf("double = %f\n", One<false>());
    return 0;
}

staseg ★★★★★
()
Ответ на: комментарий от xaizek

прошу прощения, не сразу заметил Ваш комментарий. Действительно, я неправ. Пойду курить маны)

zamazan4ik ★★
() автор топика

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

Во:

int a = (int) foo();
double b = (double) foo();
И будет сразу видно на месте какой тип тебе тут по контексту нужен, и какой именно, т.к. каст тут же. А сама пусть всегда даблю возвращает. Хотя... не поймут.

deep-purple ★★★★★
()
Ответ на: комментарий от deep-purple

И будет сразу видно на месте какой тип тебе тут по контексту нужен, и какой именно, т.к. каст тут же. А сама пусть всегда даблю возвращает.
Тебе надо разобраться с архитектурой.

staseg ★★★★★
()
Ответ на: комментарий от staseg

Ну вот, видишь, уже не поняли ))

Проблема не в том какими костылями мы это обходим, а в том, с какого хрена оно вообще понадобилось.

deep-purple ★★★★★
()
Ответ на: комментарий от deep-purple

Ато уже пыхом пованивает ... И будет сразу видно на месте какой тип тебе тут по контексту нужен, и какой именно, т.к. каст тут же. А сама пусть всегда даблю возвращает.

Это вообще какой-то лютый гогнокод.

mashina ★★★★★
()
Ответ на: комментарий от staseg

А так, в чем разница между:

int x = ((int) 3 / 2) + 1;
и
int x = foo(TO_INT, 3 / 2) + foo(PASS, 1);
Всеравно некая опция каста в том или ином виде присутствует.

deep-purple ★★★★★
()
Ответ на: комментарий от deep-purple

Нет, это костыль. Да, лютый.

Костыли делают ради достижения какой-нибудь цели по-быстрому, а ты просто беcцельно упоролся, на ровном месте.

mashina ★★★★★
()
Ответ на: комментарий от deep-purple

Аргументы будут?

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

mashina ★★★★★
()
Ответ на: комментарий от mashina

Человек пишет:

if(flag) return 1; else return 1.0;

Какую ты тут точность потерял?

каст в этом случае не нужен

А ему прямо в самый раз исходя из примера.

в плюсах такие касты не приняты
не приняты

Соседняя тема тут есть — про кол-во пробелов в отступе, у кого как принято.

deep-purple ★★★★★
()
Ответ на: комментарий от deep-purple

Какую ты тут точность потерял?

Ты же не знаешь что он хочет написать на самом деле.

А ему прямо в самый раз исходя из примера.

Это уже какой-то клинический идиотизм. ТС в примере хочет получить корректное значение нужного типа, никакого каста там нет.

mashina ★★★★★
()
Ответ на: комментарий от mashina

Ты же не знаешь

Ты тоже

хочет получить корректное значение нужного типа

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

И если я окажусь не прав (и это я, конечно, признАю в контексте применения его конкретной задачи, а остальное мы с тобой обсудили) — это не дает тебе права оскорблять.

клинический идиотизм

Подгорающий, твой.

Ждем ТСа.

deep-purple ★★★★★
()
Ответ на: комментарий от deep-purple

Я не понимаю твой вопрос, и вообще какое это имеет отношение к теме? :)

staseg ★★★★★
()
Ответ на: комментарий от zamazan4ik

//тут берём коллекцию, из неё берём два рандомных элемента, и вызываем для них foo

Попробуй распиши с конкретным примером. Получится, что всё равно типы вычислимы на этапе компиляции.

Kroz ★★★★★
()
Последнее исправление: Kroz (всего исправлений: 1)
Ответ на: комментарий от deep-purple

int a = (int) foo();

C++ C-cast оператор. Преобразования в рантайме... Зачем?! Во-первых в C++ есть свои операторы для преобразований: static_cast<T>, dynamic_cast<T>, reinterpret_cast<T>, const_cast<T>, писать длиннее, но там где они действительно нужны позволяют проще понять код, чем разбираться в этом нагромождении (). Во-вторых зачем вообще в С++ касты в рантайме? В данном случае все спокойно решается через структуру, если уж очень надо. Вот как раз C стиль пыхом попахивает, так как никакой строгой проверки типов.

anonymous
()
Ответ на: комментарий от deep-purple

смотрите, что я хотел сделать. Я хотел сделать так, чтобы в зависимости от значения аргумента функции у меня получалась либо функция int foo(bool flag /*flag == true*/), иначе же double bool(bool flag);

То есть чтобы генерировалась 2 разные функции. С чего я взял, что это можно без темплейтов сделать - ума не приложу. Вроде как не пьян даже был...

zamazan4ik ★★
() автор топика
Ответ на: комментарий от zamazan4ik

Вопрос тут скорее: для чего такое вообще понадобилось. Не с проста же на пых намекают.

Оффтоп: Хотя пыхеры на это просто кладут, принимая соглашение мол «что-то похожее на число возвращается». А последнем пыхе наконец-то нормальный тайпхинтинг появился. Так что этот прикол уже давно не актуален был морально, а теперь и технически.

deep-purple ★★★★★
()
Ответ на: комментарий от zamazan4ik
template<class T> T func(int i);

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

anonymous
()
Ответ на: комментарий от Kroz

В рантайме такое невозможно, ибо как оно будет делать

приведение типов?

в рантайме это может любой язык с динамической типизацией. С++ тоже может, с помощью folly::dynamic и подобных ей библиотек. впрочем, динамическая типизация не нужна.

anonymous
()
Ответ на: комментарий от zamazan4ik

Тут главный вопрос в том, известно ли значение аргумента в момент компиляции?

Если да - имеем две разные функции. Все возможные варианты будут лишь синтаксическим сахаром.

Если нет, то нужен тип, способный вместить все возможные типы результата. В данном случае подойдет double, union, вариантные типы и классы с перегруженными операторами преведения.

German_1984 ★★
()

Template <typename T> T f(const T &)

{Return T();}

anonymous
()
Ответ на: комментарий от German_1984

понял. Спасибо. Вы полностью ответили на мой вопрос. Имеются ли средства для динамической типизации в С++ посредством библиотек левых?

zamazan4ik ★★
() автор топика
Ответ на: комментарий от zamazan4ik

В boost'е есть тип boost::variant, у майкрософта есть VARIANT для работы с COM. Ну и тысячи велосипедов. Я даже сам как-то писал подобное.

German_1984 ★★
()
Ответ на: комментарий от zamazan4ik

в Фейсбучном Folly есть класс dynamic. Позволяет писать совсем как на этих ваших похапэ. Даже поддерживаемые типы те же. Кому приходит в голову это использовать - не понятно.

CatsCantFly
()

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

Iron_Bug ★★★★★
()

Как вообще на таком недоязыке писать что-то можно? Проще сблевать на голову страусиного трупа и больше не возвращаться к вопросу. Зачем время на это тратить?

somequest
()
Ответ на: комментарий от Kroz

и вот эти десять строк кода заставили меня,два года назад писать гдето 3Мбайта кода на джава,чтоб сделать там тожесамое(без кимпиляции в реалтайме,ибо генерировать код и пускать его в javac по ходу-худшее что может быть)

тоесть есть миллион генерируемых имен функций по ходу выполнения(классы заполняются именами функций генерируемыми,и заполнятся должны быстро,в байткоде/памяти/логике приложения а не компиляцией javac)
тоесть это <класс> А <екстенд> генерируемый_шаблон
и из класса А вызывать все сгенерированные функции

вот и все уперлось что в джаве нельзя делать динамический екстенд-надо было перекодить и создать целые тонны системной логики(на джаве) чтоб создавать такие динамические екстенды

и да весь прикол в том-что это был порт кода с С++ где именно так и было сделано-динамическая генерация зависимостей классов и их содержимых

anonymous
()

Как видите, я добился такого поведения

Нифига ты не добился. Твоя foo всегда возвращает double.

rupert ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.