C ++返回类型重载hack

时间:2010-05-12 05:16:02

标签: c++ function overloading

我很无聊并想出了这样的黑客攻击(伪代码):

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

如果使用模板,则函数的原因可以从函数参数

推断出模板参数

7 个答案:

答案 0 :(得分:5)

我宁愿使用模板专业化,只是感觉不那么“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 ++中非常复杂。

答案 1 :(得分:4)

问题是如果函数有两种返回类型,它可能会做两种不同的(替代)事情。并且在可能的范围内,每个函数/方法应该做一个连贯的事情。

答案 2 :(得分:3)

函数“function”的调用变得对上下文敏感。我想,这个技巧可以用来支持subject-oriented programming

面向主题的编程基于以下观察:对象的属性不是对象本身固有的,而是取决于谁感知该对象。例如,从人的角度来看,树不是食物,但从白蚁的角度来看,树是食物。面向对象的范式不直接支持这种观察,人们经常会遇到复杂的不自然的设计,因为他们试图将一个对象的所有不同的主观视图合并到一个实体(“类”)中,遵循不加思索的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();

请注意,树不知道吃了什么。

(确实很好的问题,让我反思很多)

答案 3 :(得分:1)

不,这不是黑客攻击。这是运算符重载的重点。只要你的超载有用,那为什么不呢?

答案 4 :(得分:1)

实际上,你似乎已经重新发明了Variant type。只需看看许多框架中存在的所有*变体类型,例如:MS使用VARIANT,Qt有QVariant

答案 5 :(得分:0)

在您的示例中,您允许转换为intfloat。只要这两个演员表演相同的基本逻辑,即operator int() { return operator float(); }我就没有问题。如果他们的行为不同,这肯定会导致一些惊喜或含糊不清。这是因为我希望数字结果具有连贯的含义。

答案 6 :(得分:0)

如果你真的是这样的话:

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

然后是的,我认为这很酷,我会把它算作黑客。

如果有效。我根本没有测试过。