簡體   English   中英

C ++返回類型重載hack

[英]C++ return type overload hack

我很無聊,想出了這樣的黑客(偽代碼):

 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);

如果使用模板,則可以從函數參數推斷函數的原因,而不是模板參數

我寧願使用模板專業化,只是感覺不那么“hacky”,可能會更快(沒有對象創建,當然,當然可以通過智能編譯器進行優化)。

但無論如何,我寧願看到類似的代碼

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 ++中非常復雜。

問題是如果函數有兩種返回類型,它可能會做兩種不同的(替代)事情。 並且在可能的范圍內,每個函數/方法應該做一個連貫的事情。

函數“function”的調用變得對上下文敏感。 我想,這個技巧可以用來支持面向主題的編程

面向主題的編程基於以下觀察:對象的屬性不是對象本身固有的,而是取決於誰感知該對象。 例如,從人的角度來看,樹不是食物,但從白蟻的角度來看,樹是食物。 面向對象的范式不直接支持這種觀察,人們經常會遇到復雜的不自然的設計,因為他們試圖將一個對象的所有不同主觀視圖合並到一個實體(“類”)中,遵循無意義的OOP指南。

因此,讓我們嘗試明確地陳述主觀感知,使用有問題的技巧來獲得情境敏感性。

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();

請注意,樹不知道吃什么。

(確實很好的問題,讓我反思很多)

不,這不是黑客攻擊。 這是運算符重載的重點。 只要你的超載有用,那么為什么不呢?

實際上,你似乎已經徹底改造了Variant類型 只需看看許多框架中存在的所有*變體類型,例如:MS使用VARIANT ,Qt具有QVariant

在您的示例中,您允許轉換為intfloat 只要這兩個強制轉換執行相同的基本邏輯,即operator int() { return operator float(); } operator int() { return operator float(); }我看不出有什么問題。 如果他們的行為不同,這肯定會導致一些驚喜或含糊不清。 這是因為我希望數字結果具有連貫的含義。

如果你真的是這樣的意思:

 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(...);

然后是的,我認為這很酷,我會把它算作黑客。

如果有效。 我根本沒有測試它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM