如何创建一个使用现有类 A 作为参数 a 的模板,并保持类 A 的实例不可复制和不可分配?
我想创建该模板以防止人们意外复制类,例如
protected
可以防止人们意外访问,并且 const
可以防止人们意外修改。
这是我的目标的简化版本:
NonCopyable<std::vector<int>> vec1{1, 2, 3};
NonCopyable<std::vector<int>> vec2(vec1); // should not compile
vec2 = vec1; // should not compile
假设我只能按原样采用原始类并且不想从该类派生,那么实现此行为的合适模板是什么? 注意:这不是如何使用不带继承的模板使现有类不可复制和不可分配?的重复。问题的编辑被审稿人拒绝,因为与最初的意图有很大的偏差。因此,这个问题必须被视为一个新问题。
如何使用不继承的模板使现有类不可复制和不可分配?首先:没有这样的模板可以防止人们在可能的情况下复制数据。 代码
这里是模板类的代码,作为包装器作为起点,以防止使用复制构造函数或复制运算符进行意外复制。
#include <vector>
template< typename T >
struct NonCopyable
{
private:
T value;
public:
NonCopyable( const NonCopyable<T>& t ) noexcept = delete;
NonCopyable( NonCopyable<T>& t ) noexcept = delete;
NonCopyable( NonCopyable<T>&& t ) noexcept = delete;
template< typename... Targs >
NonCopyable( const Targs... args ) noexcept : value{ args... } {
}
operator T&() const = delete;
NonCopyable& operator = ( const NonCopyable& ) = delete;
NonCopyable& operator = ( NonCopyable& ) = delete;
NonCopyable& operator = ( NonCopyable&& ) = delete;
};
int main( [[maybe_unused]] int argc, [[maybe_unused]]char* argv[] ) {
NonCopyable< std::vector<int> > vec1{ 1, 2, 3, 4 };
//NonCopyable< std::vector<int> > vec2( vec1 ); // would lead to the following compiler error:
/*
src/test2_2.cpp:25:48: error: use of deleted function ‘NonCopyable<T>::NonCopyable(NonCopyable<T>&) [with T = std::vector<int>]’
25 | NonCopyable< std::vector<int> > vec2( vec1 ); // should not compile
| ^
*/
//vec2 = vec1; // would lead to the following compiler error:
/*
src/test2_2.cpp:31:12: error: use of deleted function ‘NonCopyable<T>& NonCopyable<T>::operator=(NonCopyable<T>&) [with T = std::vector<int>]’
31 | vec2 = vec1;
| ^~~~
*/
return 0;
}
免责声明
因此,模板没有任何用处,但可以通过访问该值的接口来丰富。请参阅下面的示例。请同时考虑到公开的信息越多,就越容易推断出价值,从而可以创建副本。
假设,它被认为足以防止意外使用复制并使用通用接口访问
value
value
的示例。
#include <vector>
#include <functional>
#include <iostream>
template< typename T >
struct NonCopyable
{
private:
T value;
public:
NonCopyable( const NonCopyable<T>& t ) noexcept = delete;
NonCopyable( NonCopyable<T>& t ) noexcept = delete;
NonCopyable( NonCopyable<T>&& t ) noexcept = delete;
template< typename... Targs >
NonCopyable( const Targs... args ) noexcept : value{ args... } {
}
operator T&() const = delete;
NonCopyable& operator = ( const NonCopyable& ) = delete;
NonCopyable& operator = ( NonCopyable& ) = delete;
NonCopyable& operator = ( NonCopyable&& ) = delete;
template<class TReturn>
TReturn process( std::function<TReturn(const T&)> f ) {
return f( value );
}
};
int main( [[maybe_unused]] int argc, [[maybe_unused]]char* argv[] ) {
typedef std::vector<int> IntVec;
NonCopyable< IntVec > vec1{ 2, 3, 5 };
double average = vec1.template process<double>(
[]( const IntVec& vn ) {
int nSum = 0;
int nCount = 0;
for ( auto& n : vn ) {
nSum += n;
nCount++;
}
return double( nSum ) / double ( nCount );
}
);
std::cout << "average = " << average << std::endl;
//NonCopyable< std::vector<int> > vec2( vec1 ); // would lead to the following compiler error:
/*
src/test2_2.cpp:45:48: error: use of deleted function ‘NonCopyable<T>::NonCopyable(NonCopyable<T>&) [with T = std::vector<int>]’
45 | NonCopyable< std::vector<int> > vec2( vec1 ); // would lead to the following compiler error:
| ^
src/test2_2.cpp:13:5: note: declared here
13 | NonCopyable( NonCopyable<T>& t ) noexcept = delete;
| ^~~~~~~~~~~
*/
//vec2 = vec1; // would lead to the following compiler error:
/*
src/test2_2.cpp:54:12: error: use of deleted function ‘NonCopyable<T>& NonCopyable<T>::operator=(NonCopyable<T>&) [with T = std::vector<int>]’
54 | vec2 = vec1; // would lead to the following compiler error:
| ^~~~
src/test2_2.cpp:20:18: note: declared here
20 | NonCopyable& operator = ( NonCopyable& ) = delete;
| ^~~~~~~~
*/
return 0;
}
输出:
average = 3.33333
注意:正如之前所声明的,现在有人可以注入一个函数来复制该值。
内部使用继承的示例
#include <vector>
#include <functional>
#include <iostream>
template< typename T >
class NonCopyable : public T
{
public:
NonCopyable( const NonCopyable<T>& t ) noexcept = delete;
NonCopyable( NonCopyable<T>& t ) noexcept = delete;
NonCopyable( NonCopyable<T>&& t ) noexcept = delete;
template< typename... Targs >
NonCopyable( const Targs... args ) noexcept : T{ args... } {
}
operator T&() const = delete;
NonCopyable& operator = ( const NonCopyable& ) = delete;
NonCopyable& operator = ( NonCopyable& ) = delete;
NonCopyable& operator = ( NonCopyable&& ) = delete;
template<class TReturn>
TReturn process( std::function<TReturn(const T&)> f ) {
return f( *this );
}
};
int main( [[maybe_unused]] int argc, [[maybe_unused]]char* argv[] ) {
typedef std::vector<int> IntVec;
NonCopyable< IntVec > vec1{ 2, 3, 5 };
vec1.push_back( 7 );
double average = vec1.template process<double>(
[]( const IntVec& vn ) {
int nSum = 0;
int nCount = 0;
for ( auto& n : vn ) {
nSum += n;
nCount++;
}
return double( nSum ) / double ( nCount );
}
);
std::cout << "average = " << average << std::endl;
//NonCopyable< std::vector<int> > vec2( vec1 ); // would lead to the following compiler error:
/*
src/test2_3.cpp:44:48: error: use of deleted function ‘NonCopyable<T>::NonCopyable(NonCopyable<T>&) [with T = std::vector<int>]’
44 | NonCopyable< std::vector<int> > vec2( vec1 ); // would lead to the following compiler error:
| ^
src/test2_3.cpp:11:5: note: declared here
11 | NonCopyable( NonCopyable<T>& t ) noexcept = delete;
| ^~~~~~~~~~~
*/
//NonCopyable< IntVec > vec2 = vec1; // would lead to the following compiler error:
/*
src/test2_3.cpp:53:27: error: redeclaration of ‘NonCopyable<std::vector<int> > vec2’
53 | NonCopyable< IntVec > vec2 = vec1; // would lead to the following compiler error:
| ^~~~
src/test2_3.cpp:44:37: note: ‘NonCopyable<std::vector<int> > vec2’ previously declared here
44 | NonCopyable< std::vector<int> > vec2( vec1 ); // would lead to the following compiler error:
| ^~~~
*/
return 0;
}
average = 4.25
最后一句话
所提出的方法可以防止意外复制(“不可复制且不可转让”)。
protected
值阻止直接访问,并且仍然可以在派生类中进行修改,并且以同样的方式,这也适用于关键字
const
。
兼容性注意:所有代码均已使用-std=c++20
-std=c++11
进行编译。