4

I have a CRTP base class as follows:

template<typename Derived, size_t DIMS>
class Base {
public:
    // here is I think where the problem is
    inline const Derived& self() const {return *static_cast<const Derived*>(this);}
};

Then the derived class is defined as

template<typename T, size_t ... Rest>
class Derived: public Base<Derived<T,Rest...>,sizeof...(Rest)> {
public:

    Derived() = default;

    // This constructor binds any arbitrary expression to Derived
    template<typename Expr, size_t DIMS>
    inline Derived(const Base<Expr,DIMS>& src_) {
        const Expr &src = src_.self();
        print(src.rhs);
    }
};

with defining my own operators in mind, I also have the following AddOperator which also inherits from base

template<typename TLhs, typename TRhs, size_t DIMS>
struct AddOperator: public Base<AddOperator<TLhs, TRhs, DIMS>,DIMS> {
    AddOperator(const TLhs& lhs, const TRhs& rhs) : lhs(lhs), rhs(rhs) {
        print(rhs);
    }
    const TLhs &lhs;
    const TRhs &rhs;
};

Then the operator+ overload between a Derived type and a primitive type returns only a proxy/expression of sorts:

template<typename TLhs, typename TRhs, size_t DIM0,
         typename std::enable_if<!std::is_arithmetic<TLhs>::value &&
                                 std::is_arithmetic<TRhs>::value,bool>::type = 0 >
inline AddOperator<TLhs, TRhs, DIM0> 
operator+(const Base<TLhs,DIM0> &lhs, TRhs rhs) {
  return AddOperator<TLhs, TRhs, DIM0>(lhs.self(), rhs);
}

However, when I call this under clang I get garbage values for rhs of AddOperator. Here is an example:

int main() {

    Derived<double,2,2> g;
    Derived<double,2,2> x = g+28;

    return 0;
}

The other overloads when both lhs and rhs in AddOperator are of type Derived do not have this problem.

This problem happens only under clang. gcc compiled code seems to run fine. Does anyone know where the problem is?

Full Demo Here

4

1 回答 1

6

你的问题是你有一个悬空的参考。

operator+中,您按值获取TRhs( int),然后AddOperator<...>使用对它的引用构造 an。g+28返回时,对象AddOperator<...>仍然具有对参数的引用rhs- 其生命周期现已结束。

您打印的垃圾是访问被破坏对象的结果 - 这是未定义的行为。在 clang 上,这表现为为您打印一个垃圾值,在 gcc 上它恰好可以工作。未定义的行为就是这样棘手的。


现在,看似“明显”的解决方法是通过引用更改operator+为. 这将通过包含调用的完整表达式的结束来延长临时的生命周期- 所以现在您的打印语句可以保证工作。至少,直到行尾。构造完成后,引用将再次悬空。rhsconst28x

于 2016-05-25T15:36:16.113 回答