c++ - 表达式模板不适用于 clang 下的原始类型重载

标签 c++ c++11 expression-templates

我有一个 CRTP基类如下:

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

那么派生类定义为

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

考虑到定义我自己的运算符,我还有以下 AddOperator 也继承自 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;
};

然后 Derived 类型和原始类型之间的 operator+ 重载仅返回各种代理/表达式:

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

但是,当我在 clang 下调用它时,我得到了 AddOperatorrhs 的垃圾值。这是一个例子:

int main() {

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

    return 0;
}

AddOperator中的lhsrhs都是Derived类型时的其他重载没有这个问题.

此问题仅在 clang 下发生。 gcc 编译后的代码似乎运行良好。有谁知道问题出在哪里?

Full Demo Here

最佳答案

你的问题是你有一个悬空引用。

operator+ , 你拿一个 TRhs ( int ) 按值,然后构造一个 AddOperator<...>并引用它。当g+28返回,AddOperator<...>对象仍然引用参数 rhs - 其生命周期现已结束。

您正在打印的垃圾是访问已销毁对象的结果——这是未定义的行为。在 clang 上,这表现为为您打印垃圾值,在 gcc 上它恰好有效。未定义的行为就像那样棘手。


现在,看似“显而易见”的解决方法是更改​​ operator+采取rhs引用const .这将延长临时 28 的生命周期到包含调用的完整表达式的末尾 - 所以现在您的打印语句可以保证工作。至少,直到行尾。在x之后构造完成后,引用将再次悬挂。

关于c++ - 表达式模板不适用于 clang 下的原始类型重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37441136/

相关文章:

c++ - 添加图像到 QQuickView

c++ - 从 std::vector 删除元素后更新存储的索引

c++ - Boost.原型(prototype) : Is it possible for Proto transforms to evaluate a mixture expression of matrix & vector?

c++ - 在运行时确定 *.dll 或 *.so 的路径

c++ - 当前时间作为创建文件的字符串

c++ - 有谁知道 endl(cout) 和 cout << endl 之间的区别?

c++ - Visual Studio 2012 中的智能指针错误

c++ - 过渡到使用 noexcept 隐式声明析构函数的 C++11

c++ - 为什么 std::basic_string 不支持通过表达式模板进行连接?

c++ - 使用通过 auto 关键字创建的类型的表达式模板中的段错误