1

I've looked at this answer Can you make custom operators in C++? and tried to implement a custom power operator denoted by <power>, using some proxy objects. However, I have a very strange bug which makes my program only work when I print out a variable (The variable x in the definition of the class PowerExpression).

Here's my code:

//
//  Power.hpp
//  Draft1.0
//
//  Created by CYRUS LINDEN on 1/1/21.
//  Copyright © 2021 CYRUS LINDEN. All rights reserved.
//

#ifndef Power_hpp
#define Power_hpp

#include <stdio.h>
//
//  Power.hpp
//  Experiments
//
//  Created by CYRUS LINDEN on 1/1/21.
//  Copyright © 2021 CYRUS LINDEN. All rights reserved.
//
#include <cmath>
#include <iostream>
const struct power_ {} power;

template <typename T>
struct PowerProxy
{
    PowerProxy(const T& t): t_(t) {}
    const T& t_;
    inline operator T() const {
        return t_;
    }
};
template <typename T>
class BasePowerExpression;
template <typename T, typename U>
class PowerExpression {
public:
    PowerExpression(const T& lhs, const U& rhs) : lhs_(lhs) , rhs_(rhs) {}
public:
    const T& lhs_;
    const U& rhs_;
    inline operator T() const {
        //std::cout << typeid(rhs_).name();
        const T& x = static_cast<T>(rhs_);
        // THIS IS THE LINE THAT CAUSES THE BUG. IF IT IS REMOVED, THE ANSWER IS 0.
        std::cout << x << '\n';
        
        return std::pow(lhs_, x);
    }
};
template <typename T>
class BasePowerExpression{
public:
    const T& lhs_;
    const T& rhs_;

    BasePowerExpression(const T& lhs, const T& rhs) : lhs_(lhs) , rhs_(rhs) {}
    inline operator T() const {
        return std::pow(lhs_, rhs_);
    }

    
};
template <typename T>
inline auto operator<(const T& lhs, const power_& rhs)
{
    return PowerProxy<T>(lhs);
}

template <typename T>
inline auto operator<(const BasePowerExpression<T>& lhs, const power_& rhs)
{
    return lhs;
}
template <typename T, typename U>
inline auto operator<(const PowerExpression<T , U>& lhs, const power_& rhs)
{
    return lhs;
}


template <typename T>
inline auto operator>(const PowerProxy<T>& lhs, const T& rhs)
{
    return BasePowerExpression(lhs.t_, rhs);
}
template <typename T>
inline auto operator>(const BasePowerExpression<T>& lhs, const T& rhs)
{
    return PowerExpression(lhs.lhs_, BasePowerExpression(lhs.rhs_, rhs));
 ;
    
}
template <typename T, typename U>
inline auto operator> (const PowerExpression<T , U>& lhs, const T& rhs) {

        return PowerExpression(lhs.lhs_, PowerExpression(lhs.rhs_, rhs));
        
}

#endif /* Power_hpp */

and when trying to use it in main.cpp:


int main() {
   std::cout << (2 <power> 2 <power> 3);
   return 0;

}

This compiles fine and works fine and prints 256 . However, if I remove the line where I print x in the definition of class PowerExpression, this just prints 0. This is very strange. I think my code must have some undefined behaviour in it, but I can't seem to find any. Can anyone help me out here?

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
SomeProgrammer
  • 1,134
  • 1
  • 6
  • 12
  • 8
    I am unable to answer this question because the shared code has an `All rights reserved` text in it. – Cem Jan 01 '21 at 20:30
  • 1
    You can't make custom operators because there is no way to provide the precedence ranking of the custom operator, as well as the evaluation direction. – Thomas Matthews Jan 01 '21 at 20:38
  • 1
    @Cem :P I believe the text is pointless, and OP is effectively dual-licensing this under CC-BY-SA. – HolyBlackCat Jan 01 '21 at 20:39
  • @Cem would `All rights reserved` prevent someone from diagnosing bugs in protected code? – Spidey Jan 01 '21 at 20:40
  • Is there any need for both `BasePowerExpression` _and_ `PowerExpression` ? Can't this be one class? `PowerExpression(lhs.lhs_, PowerExpression(lhs.rhs_, rhs))` - why are you powering it twice? – KamilCuk Jan 01 '21 at 20:40
  • 1
    Using an address sanitizer reveals the issue. See [demo on godbolt](https://godbolt.org/z/nK9vW1). – IlCapitano Jan 01 '21 at 20:43
  • 1
    @Spidey I guess not. I just wanted to jokingly make a point since I believe sharing code to be used freely would be nice, since everyone is helping others on SO :) – Cem Jan 01 '21 at 20:46
  • If you remove reference from `t_`, `lhs_` and `rhs_` classes members, it will print 256 (with or without printing `x`) – Phil1970 Jan 02 '21 at 01:07
  • 1
    @ThomasMatthews: this custom operator is an operator by appearance only. '<` and '>' are the operators being overloaded so the "custom operator" has the precedence and associativity of those. – Michael Burr Jan 02 '21 at 08:02

0 Answers0