gpt4 book ai didi

c++ - 模板化特殊成员(operator=)的重载解析

转载 作者:行者123 更新时间:2023-11-30 05:00:50 25 4
gpt4 key购买 nike

上下文:试图实现 copy and swap模板化自制 shared_ptr 上的成语。我无法调用此函数:

    template<typename U>
shared_ptr<T>& operator=(shared_ptr<U> rhs)
{
static_assert(std::is_base_of<T, U>::value);
swap(*this, rhs);
return *this;
}

去除不必要的代码:

以下代码无法编译。 “x=y”行是尝试使用:

    foo<T>& operator=(const foo<U>& ptr) = delete;

如果我删除/注释已删除的函数行。意思是如果我不定义它们,编译器会为我做,代码会编译。但是,编译器生成的特殊成员将优先于我的运算符,不会被调用。

template<typename T> 
class foo
{
public:

// copy&swap
template<typename U>
foo<T>& operator=(foo<U> rhs)
{
// whatever is needed swap and all
return *this;
}

template<typename U>
foo<T>& operator=(const foo<U>& ptr) = delete;
template<typename U>
foo<T>& operator=(foo<U>&& ptr) = delete;

foo<T>& operator=(foo<T>&& ptr) = delete;
};

int main()
{
foo<int> x,y;
x = y;
return 0;
}

问题:

  • 这里我不清楚重载决议。为什么一个签名优于另一个签名?
  • 如果函数被删除,我理解这不是“替换失败”,但它仍然是签名级别的失败,而不是主体内部的失败,为什么编译器停止寻找匹配项?
  • 有什么解决方案可以让函数被调用?


编辑/回答

到目前为止,这是正确的版本:

  • 非模板构造函数(移动/复制)被标记为显式,以便将 foo 分配给 foo 调用模板版本。
  • 添加了适当的静态断言,以便转换 U/T 有意义
  • 参数被完美转发给分配/移动内部函数

代码:

#include <iostream>
template<typename T>
class foo
{
private:
template <typename U> friend class foo;

template<typename U>
void assign(const foo<U>& other)
{
static_assert(std::is_base_of<T, U>::value || std::is_convertible<U, T>::value);
std::cout << "templated assign function" << std::endl;
this->data = other.data;
}

template<typename U>
void move(foo<U>&& other)
{
static_assert(std::is_base_of<T, U>::value || std::is_convertible<U, T>::value);
std::cout << "templated move function" << std::endl;
this->swap(*this, other);
}
public:

template<class X, class Y> void swap(foo<X>& left, foo<Y>& right) noexcept
{
std::cout << "templated swap function" << std::endl;
std::swap(left.data, right.data);
}

void swap(foo<T>& left, foo<T>& right) noexcept
{
std::cout << "swap function" << std::endl;
std::swap(left.data, right.data);
}

foo() {}

explicit foo(foo<T>&& other)
{
std::cout << "move constructor foo(foo&& other)" << std::endl;
move(std::forward<decltype(other)>(other));
}


explicit foo(const foo<T>& other)
{
std::cout << "copy constructor foo(const foo& other)" << std::endl;
assign(std::forward<decltype(other)>(other));
}

template<typename U>
foo(foo<U>&& other)
{
static_assert(std::is_base_of<T, U>::value || std::is_convertible<U, T>::value);
std::cout << "templated move constructor template<typename U> foo(foo<U>&& other)" << std::endl;
move(std::forward<decltype(other)>(other));
}

template<typename U>
foo(const foo<U>& other)
{
static_assert(std::is_base_of<T, U>::value || std::is_convertible<U,T>::value);
std::cout << "templated copy constructor template<typename U> foo(const foo<U>& other)" << std::endl;
assign(std::forward<decltype(other)>(other));
}

// copy&swap
template<typename U>
foo<T>& operator=(foo<U> rhs)
{
static_assert(std::is_base_of<T, U>::value || std::is_convertible<U, T>::value);

std::cout << "templated assignement template<typename U> foo<T>& operator=(foo<U> rhs)" << std::endl;

auto tmp = rhs.data;
rhs.data = reinterpret_cast<U*>(data);
data = reinterpret_cast<T*>(tmp);

return *this;
}

foo<T>& operator=(foo<T> rhs)
{
std::cout << "assignement foo<T>& operator=(foo<T> rhs)" << std::endl;

std::swap(rhs.data,data);
return *this;
}

private:
T * data;
};

int main()
{
foo<int> x,y;
const foo<int>& cy = y;

foo<short> z, w;
x = y;
x = cy;
x = std::move(y);
x = z;
x = std::move(w);
return 0;
}

最佳答案

  1. operator=(const foo&)仅 cv 限定符不同,将优先于模板
  2. = delete导致 operator=(const foo&)被禁止。它不仅会阻止编译器生成它。

应该这样做:

#include <tuple>
#include <iostream>

template<typename T>
class foo
{
private:
template <typename U> friend class foo;

foo& assign(T rhs)
{
std::swap(data, rhs);
return *this;
}

public:


template<typename U>
foo& operator=(const foo<U>& rhs)
{
return assign(rhs.data);
}

template<typename U>
foo& operator=(foo<U>&& rhs)
{
return assign(std::move(rhs.data));
}

foo& operator=(const foo& rhs)
{
return assign(rhs.data);
}

foo& operator=(foo&& rhs)
{
return assign(std::move(rhs.data));
}

private:
T data;
};

int main()
{
foo<int> x,y;
const foo<int>& cy = y;

foo<short> z, w;
x = y;
x = cy;
x = std::move(y);
x = z;
x = std::move(w);
return 0;
}

Edit1: 添加了成员​​并调用交换。

Edit2: 更改分配以占用 T按值而不是 foo<T>添加移动任务

注意:现在使用 T 的转换构造函数分配 foo 时不同类型 ( U )

关于c++ - 模板化特殊成员(operator=)的重载解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50551320/

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