Возврат C++ вводит взлом перегрузки

Я скучал и придумал такой взлом (псевдокод):

 1 struct proxy {
 2     operator int(); // int function
 3     operator double(); // double function
 4     proxy(arguments);
 5     arguments &arguments_;
 6 };
 7
 8 proxy function(arguments &args) {
 9     return proxy(args);
10 }
11 int v = function(...);
12 double u = function(...);

действительно ли это является злым для использования в реальном коде?

мой возможный сценарий использования является, например, продуктом элементов массива, которые не могут переполниться:

int size(short *array);
short size(short *array);

Причина функции, в случае, если Вы используете шаблоны, чем шаблонные параметры может быть выведена из аргументов функции

13
задан AstroCB 31 August 2014 в 01:35
поделиться

7 ответов

Я бы предпочел использовать специализацию шаблона, просто кажется менее "хакерским" и, вероятно, будет быстрее (без создания объектов, хотя, конечно, это можно оптимизировать с помощью интеллектуального компилятора).

Но в любом случае, я бы предпочел увидеть код вроде

template<typename T> T function();

template<> int function() {
    return 1;
}

template<> float function() {
    return 1.0;
}

....
int a = function<int>();
float b = function<float>();

Хотя в вашем коде нет ничего плохого, особенно если вы держитесь подальше от числовых типов / указателей, поскольку в противном случае могут возникнуть непредвиденные эффекты, правила преобразования довольно сложны в C ++.

5
ответ дан 2 December 2019 в 00:30
поделиться

Проблема в том, что если функция имеет два возвращаемых типа, она, вероятно, выполняет два разных (альтернативных ) вещи . И, насколько это возможно, каждая функция / метод должна выполнять одно связное действие.

4
ответ дан 2 December 2019 в 00:30
поделиться

В вашем примере вы разрешаете приведение типов к int и float . Пока эти два преобразования выполняют одну и ту же базовую логику, то есть operator int () {return operator float (); } Не вижу проблем. Если они будут вести себя по-другому, это определенно может привести к некоторым сюрпризам или двусмысленностям. Это потому, что я ожидал, что числовые результаты будут иметь логичное значение.

0
ответ дан 2 December 2019 в 00:30
поделиться

Нет, и это не взлом. В этом весь смысл перегрузки оператора. Если ваши перегрузки служат определенной цели, почему бы и нет?

1
ответ дан 2 December 2019 в 00:30
поделиться

Если вы действительно имеете в виду что-то вроде этого:

 1 struct proxy {
 2     operator long() { return refs.first; } // long has greater precision
 3     operator double() { return refs.second; } // double has greater range
 4     proxy( long const &, double const & );
 5     pair< long const &, double const & > refs;
 6 };
 7
 8 proxy function() {
 9     return proxy( numeric_limits<long>::max() + 1,
                     double( numeric_limits<long>::max() ) );
10 }
11 int v = function(...);
12 double u = function(...);

Тогда да, я думаю, это круто, и я бы посчитал это хаком.

Если это работает. Я не тестировал это вообще.

0
ответ дан 2 December 2019 в 00:30
поделиться

На самом деле кажется, что вы заново изобрели Тип варианта . Просто взгляните на все * типы вариантов, которые присутствуют во многих фреймворках, например: MS использует VARIANT , Qt имеет QVariant .

1
ответ дан 2 December 2019 в 00:30
поделиться

Вызов функции "function" стал как бы контекстно чувствительным. Я полагаю, что этот трюк можно использовать для поддержки предметно-ориентированного программирования.

Субъектно-ориентированное программирование основано на наблюдении, что свойства объекта не присущи самому объекту, а зависят от того, кто воспринимает этот объект. Например, с точки зрения человека, дерево не является пищей, но с точки зрения термита, дерево является пищей. Объектно-ориентированная парадигма не поддерживает это наблюдение напрямую, и люди часто приходят к сложным неестественным конструкциям, потому что они пытаются включить все различные субъективные взгляды на объект в одну сущность ("класс"), бездумно следуя рекомендациям ООП.

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

template<class FoodSource>
class FoodFrom {};
//forward declarations
class Tree;
class Termite;
class Human;

//property "food" of a tree
template<>
class FoodFrom<Tree>
{
public:
    FoodFrom(Tree& _tree): tree(_tree) {}

    //termite perception of tree as food
    operator FoodFor<Termite>()
    {
        int happiness_increase = 5;
        tree.mass -= 10;
        return FoodFor<Termite>(happiness_increase);
    }
    //human perception of tree as food
    operator FoodFor<Human>()
    {
        int happiness_increase = 0;
        return FoodFor<Human>(happiness_increase);
    }
private:
    Tree& tree;
};
//property "food" of a termite
template<>
class FoodFrom<Termite>
{
public:
    FoodFrom(Termite& _termite): termite(_termite) {}
    //human perception of termite as food
    operator FoodFor<Human>()
    {
        int happiness_increase = -100;
        //apparently, the termite ought to be terminated due to such a violent act
        termite.~Termite();
        return FoodFor<Human>(happiness_increase);
    }
private:
    Termite& termite;
};

//simple class FoodFor, just for demonstration purposes
class FoodBase
{
public:
    FoodBase(int _value) : value(_value) {}
    int value;
};
template<class T>
class FoodFor: public FoodBase
{
public:
    FoodFor(): FoodBase(0) {}
    FoodFor(int _value) : FoodBase(_value) {}
};

class AliveBeing
{
public:
    AliveBeing(): happiness(100) {}
    bool is_happy()
    {
        return happiness > 0;
    }
    void eat()
    {
        happiness += getMeal()->value;
    }
private:
    int happiness;
    virtual FoodBase* getMeal() = 0;
};
class Tree: public AliveBeing
{
public:
    FoodFrom<Tree> getFood(); //see definition below
    float mass;
    //...
private:
    //we don't call getMeal for a tree in this demo
    virtual FoodBase* getMeal() { return NULL; }
};

class Termite: public AliveBeing
{
public:
    FoodFrom<Termite> getFood(); //see definition below
    FoodFor<Termite> meal;
private:
    virtual FoodBase* getMeal() { return &meal; }
};

class Human: public AliveBeing
{
public:
    FoodFor<Human> meal;
private:
    virtual FoodBase* getMeal() { return &meal; }
};

//return proxy "FoodFrom" to "overload" return type
FoodFrom<Tree> Tree::getFood()
{ return FoodFrom<Tree>(*this); }
FoodFrom<Termite> Termite::getFood()
{ return FoodFrom<Termite>(*this); }

//usage
    Tree tree;
    Termite funny_bug;
    //funny_bug gets its perceived value of eating tree
    funny_bug.meal = tree.getFood();
    funny_bug.eat();
    if(funny_bug.is_happy())
        funny_bug.goFindThirdPlace();

    //...

    Human joel;
    //joel get its perceived value of eating tree
    joel.meal = tree.getFood();
    joel.eat();

    //...

    if(joel.see(funny_bug))
    {
        joel.meal = funny_bug.getFood();
        joel.eat();
    }
    if(joel.is_happy())
        joel.writeAnotherGreatArticle();

Заметим, что дерево не знает, что его ест.

(отличный вопрос, заставивший меня задуматься над ним)

3
ответ дан 2 December 2019 в 00:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: