gpt4 book ai didi

c++ - 通过按值传递的 CRTP 模式的单元化拷贝

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:43:58 24 4
gpt4 key购买 nike

我正在使用 CRTP 模式,并尝试定义适用于其实现的运算符。我发现了未初始化对象的一种奇怪行为。

CRTP 基类:

template < class C >
struct CRTP
{
using self_t = C;
const self_t& self() const
{ return static_cast<const self_t&>(*this); }
self_t& self()
{
const CRTP& cs = static_cast<const CRTP&>(*this);
return const_cast<self_t&>(cs.self());
}
void printValue()
{ cout << "CRTP value : " << self().getValue() << endl; }
};

实现 1:

struct Impl : public CRTP<Impl> {
Impl() = default;
Impl(Impl&&) = default;
Impl(const Impl&) = default;
explicit
Impl(int i) : v(i) { }

friend void swap(Impl& l, Impl& r)
{ using std::swap; swap(l.v, r.v); }

Impl& operator=(Impl o)
{ swap(*this, o); return *this; }

int getValue() const
{ return v; }

private:
int v;
};

实现 2:

template < class Arg >
struct Neg : public CRTP< Neg<Arg> >
{
Neg() = default;
Neg(Neg&&) = default;
Neg(const Neg&) = default;
explicit
Neg(Arg arg) : a(arg) { }

friend void swap(Neg& l, Neg& r)
{ using std::swap; swap(l.a, r.a); }

Neg& operator=(Neg o)
{ swap(*this, o); return *this; }

int getValue() const
{ return -a.getValue(); }
private:
Arg a;
};

运算符(operator! 工作正常,operator~ 显示问题):

template < class C >
Neg<C> operator~(CRTP<C> v)
{ return Neg<C>(std::move(v.self())); }

template < class C >
Neg<C> operator-(const CRTP<C>& v)
{ return Neg<C>(v.self()); }

template < class C >
Neg<C> operator-(CRTP<C>&& v)
{ return Neg<C>(std::move(v.self())); }

现在有了一个简单的 main:

int main(void)
{
auto n = -Impl(10);
n.printValue();
n = ~Impl(20);
n.printValue();
}

用 gcc 编译,我有:

CRTP value : -10
CRTP value : 0

用 CLANG 编译我得到:

CRTP value : -10
CRTP value : -1186799704

现在我有两个问题:

  • 这是行为标准吗?即使我删除了默认值,它也会发生 构造函数
  • 如何在“按值传递”中实现运算符style”?我有 n 元运算符,我想使用可变参数模板,我无法枚举左值和右值引用的每个组合。

最佳答案

您在 operator ~ 的参数中对对象进行切片.你正在服用 CRTP<C>按值(value),这意味着超出 CRTP 的任何东西子对象(例如成员 va )将被切掉。然后,您将通过转换 CRTP<C> 类型的切片对象来调用未定义的行为。输入 C , 它不是。

当你按值传递时,你需要传递正确类型的值——对象实际的类型。您的对象不是 CRTP<C> 类型对于任何 C , 它们属于 derived 来自 CRTP<C> 的类型(对于一些 C )。

如果您想保留按值传递签名,则必须接受任何内容并使用 SFINAE 检查是否存在正确的基类:

template <class C>
typename std::enable_if<std::is_base_of<CRTP<C>, C>::value, Neg<C>>::type operator~ (C v)
{ return Neg<C>(std::move(v.self())); }

或者您可以使用完美转发,使用相同的技巧。

关于c++ - 通过按值传递的 CRTP 模式的单元化拷贝,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32047384/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com